From d446278c888891b351563a3d9201d1b4c032e3a1 Mon Sep 17 00:00:00 2001 From: Erwin Waterlander Date: Thu, 27 Oct 2022 17:19:25 +0200 Subject: [PATCH] Initial source commit. --- .gitignore | 2 + asm/.classpath | 6 + asm/.gitignore | 1 + asm/.project | 17 + asm/src/console/ASM.java | 24 + asm/src/console/CommandLineParser.java | 248 ++++ asm/src/console/Commands.java | 61 + asm/src/console/Console.java | 112 ++ asm/src/dialogs/CalculationDialog.java | 251 ++++ asm/src/dialogs/OpenSignalDialog.java | 89 ++ asm/src/dialogs/OperationsDialog.java | 127 ++ asm/src/dialogs/SaveSignalDialog.java | 124 ++ asm/src/dialogs/SourceDialog.java | 226 ++++ asm/src/dialogs/TransformationsDialog.java | 190 +++ asm/src/dialogs/WindowingDialog.java | 97 ++ asm/src/exceptions/SignalDoesNotExist.java | 29 + asm/src/math/Calculations.java | 869 +++++++++++++ asm/src/math/ConvCorr.java | 249 ++++ asm/src/math/FFT.java | 78 ++ asm/src/math/MathBase.java | 36 + asm/src/math/Transformations.java | 509 ++++++++ asm/src/signals/PlotCommands.java | 235 ++++ asm/src/signals/Signal.java | 509 ++++++++ asm/src/signals/SignalWindow.java | 1221 ++++++++++++++++++ asm/src/signals/Sources.java | 660 ++++++++++ asm/src/signals/SourcesBase.java | 36 + asm/src/signals/Windowing.java | 240 ++++ asm/src/util/Util.java | 27 + doc/asm.tex | 1328 ++++++++++++++++++++ doc/asmdata.eps | 431 +++++++ doc/asmdata.obj | 141 +++ doc/copyright.txt | 4 + doc/makefile | 16 + doc/readme.txt | 167 +++ doc/todo.txt | 92 ++ doc/whatsnew.txt | 142 +++ 36 files changed, 8594 insertions(+) create mode 100644 .gitignore create mode 100644 asm/.classpath create mode 100755 asm/.gitignore create mode 100644 asm/.project create mode 100644 asm/src/console/ASM.java create mode 100644 asm/src/console/CommandLineParser.java create mode 100644 asm/src/console/Commands.java create mode 100644 asm/src/console/Console.java create mode 100644 asm/src/dialogs/CalculationDialog.java create mode 100644 asm/src/dialogs/OpenSignalDialog.java create mode 100644 asm/src/dialogs/OperationsDialog.java create mode 100644 asm/src/dialogs/SaveSignalDialog.java create mode 100644 asm/src/dialogs/SourceDialog.java create mode 100644 asm/src/dialogs/TransformationsDialog.java create mode 100644 asm/src/dialogs/WindowingDialog.java create mode 100644 asm/src/exceptions/SignalDoesNotExist.java create mode 100644 asm/src/math/Calculations.java create mode 100644 asm/src/math/ConvCorr.java create mode 100644 asm/src/math/FFT.java create mode 100644 asm/src/math/MathBase.java create mode 100644 asm/src/math/Transformations.java create mode 100644 asm/src/signals/PlotCommands.java create mode 100644 asm/src/signals/Signal.java create mode 100644 asm/src/signals/SignalWindow.java create mode 100644 asm/src/signals/Sources.java create mode 100644 asm/src/signals/SourcesBase.java create mode 100644 asm/src/signals/Windowing.java create mode 100644 asm/src/util/Util.java create mode 100644 doc/asm.tex create mode 100644 doc/asmdata.eps create mode 100644 doc/asmdata.obj create mode 100644 doc/copyright.txt create mode 100644 doc/makefile create mode 100644 doc/readme.txt create mode 100644 doc/todo.txt create mode 100644 doc/whatsnew.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57901c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.bak +.settings diff --git a/asm/.classpath b/asm/.classpath new file mode 100644 index 0000000..9a525f5 --- /dev/null +++ b/asm/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/asm/.gitignore b/asm/.gitignore new file mode 100755 index 0000000..ae3c172 --- /dev/null +++ b/asm/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/asm/.project b/asm/.project new file mode 100644 index 0000000..7193b12 --- /dev/null +++ b/asm/.project @@ -0,0 +1,17 @@ + + + ASM + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/asm/src/console/ASM.java b/asm/src/console/ASM.java new file mode 100644 index 0000000..a12e7ba --- /dev/null +++ b/asm/src/console/ASM.java @@ -0,0 +1,24 @@ +package console; + +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +public class ASM extends Application { + + @Override + public void start(Stage primaryStage) throws Exception { + + VBox root = new VBox(); + Scene scene = new Scene(root, 600, 400); + new Console(root, primaryStage); + primaryStage.setScene(scene); + primaryStage.setTitle("ASM Console"); + primaryStage.show(); + } + + public static void main(String[] args) { + launch(args); + } +} diff --git a/asm/src/console/CommandLineParser.java b/asm/src/console/CommandLineParser.java new file mode 100644 index 0000000..fa97b91 --- /dev/null +++ b/asm/src/console/CommandLineParser.java @@ -0,0 +1,248 @@ +package console; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import exceptions.SignalDoesNotExist; +import math.Calculations; +import math.ConvCorr; +import math.Transformations; +import signals.PlotCommands; +import signals.Signal; +import signals.SignalWindow; +import signals.Sources; +import signals.Windowing; + +public class CommandLineParser { + private final Sources sources; + private final Windowing windowing; + private final Calculations calculations; + private final Transformations transformations; + private final PlotCommands plotCommands; + private final ConvCorr convcorr; + private final Console console; + private final Commands commands = new Commands(); + private boolean don = true; + private boolean bon = false; + private File signalDirectory = new File(System.getProperty("user.home")); + Map signals; + + public CommandLineParser(Map signals, Console console) { + this.signals = signals; + this.sources = new Sources(signals, this); + this.windowing = new Windowing(signals, this); + this.calculations = new Calculations(signals, this); + this.transformations = new Transformations(signals, this); + this.plotCommands = new PlotCommands(signals, this); + this.convcorr = new ConvCorr(signals, this); + this.console = console; + } + + public String getString(List args, String name, String defaultValue) { + if (args.isEmpty()) { + return defaultValue; + } else { + String result = args.get(0) == null || args.get(0).isEmpty() ? defaultValue : args.get(0); + args.remove(0); + return result; + } + } + + public void print(String message) { + console.print(message); + } + + public void println(String message) { + console.println(message); + } + + public int getInt(List args, String name, int min, int max, int defaultValue) { + int result; + if (args.isEmpty()) { + return defaultValue; + } else { + try { + result = args.get(0) == null || args.get(0).isEmpty() || args.get(0).equals(".") ? defaultValue + : Integer.parseInt(args.get(0)); + } catch (NumberFormatException e) { + println("error: invalid expression for (integer) " + name); + result = defaultValue; + } + args.remove(0); + if (result < min) + return min; + else if (result > max) + return max; + else + return result; + } + } + + public double getDouble(List args, String name, double min, double max, double defaultValue) { + double result; + if (args.isEmpty()) { + return defaultValue; + } else { + try { + result = args.get(0) == null || args.get(0).isEmpty() || args.get(0).equals(".") ? defaultValue + : Double.parseDouble(args.get(0)); + } catch (NullPointerException e) { + result = defaultValue; + } catch (NumberFormatException e) { + println("error: invalid expression for (double) " + name); + result = defaultValue; + } + args.remove(0); + if (result < min) + return min; + else if (result > max) + return max; + else + return result; + } + } + + int parseCommand(String command_with_args) { + + if (command_with_args == null) { + return 0; + } + String cmd = command_with_args.trim(); + if (cmd.isEmpty()) { + return 0; + } + + String[] args = cmd.split("\\s+"); + List argList = new ArrayList<>(Arrays.asList(args)); + return parseCommand(argList); + } + + public void showSignal(Signal s, boolean override) { + if (!don && !override) + return; + if (s == null) + return; + SignalWindow w = s.getWindow(); + if (w == null) { + w = new SignalWindow(s, this, signals); + } else { + w.show(bon); + } + } + + public void closeSignal(Signal s) { + if (s == null) + return; + SignalWindow w = s.getWindow(); + if (w == null) { + return; + } else { + w.close(); + } + } + + public void showConsole() { + console.show(); + } + + private void printCommand(List argList) { + StringBuffer line = new StringBuffer(); + line.append(">"); + for (String arg : argList) { + if (arg == null || arg.isEmpty()) { + line.append(" ."); + } else { + line.append(" " + arg); + } + } + println(line.toString()); + } + + public int parseCommand(List argList) { + + if (argList == null || argList.isEmpty()) { + return 0; + } + printCommand(argList); + String command = argList.get(0); + argList.remove(0); + List cmdMatches = commands.getCommand(command); + if (cmdMatches.size() > 1) { + println("Ambiguous command: " + command); + return 0; + } else if (cmdMatches.size() == 1) + command = cmdMatches.get(0); + if (!argList.isEmpty() && argList.get(0) != null && argList.get(0).matches("^\\?$|-h")) { + String help = commands.getHelp(command); + if (help != null) { + println(help); + return 0; + } + } + + try { + if (command.equals("list")) { + for (String signalName : signals.keySet()) { + println(signalName); + } + } else if (command.equals("?")) { + List cmds = commands.getAllCommands(); + for (String cmd : cmds) + println(cmd); + } else if (command.equals("don")) { + don = true; + println("Display is ON"); + } else if (command.equals("doff")) { + don = false; + println("Display is OFF"); + } else if (command.equals("bon")) { + bon = true; + println("Bar graph is ON"); + } else if (command.equals("boff")) { + bon = false; + println("Bar graph is OFF"); + } else if (command.equals("exit") || command.equals("quit")) { + System.exit(0); + } else if (PlotCommands.plotcommands.containsKey(command)) { + Signal s = plotCommands.PlotCommandsCi(argList, command); + showSignal(s, command.equals("display")); + } else if (Sources.functions.containsKey(command)) { + Signal s = sources.SourcesCi(argList, command); + showSignal(s, false); + } else if (Windowing.windows.containsKey(command)) { + Signal s = windowing.WindowCi(argList, command); + showSignal(s, false); + } else if (Calculations.calculations.containsKey(command)) { + Signal s = calculations.CalculateCi(argList, command); + showSignal(s, false); + } else if (Transformations.transformations.containsKey(command)) { + Signal s = transformations.TransformationCi(argList, command); + showSignal(s, false); + } else if (ConvCorr.convcorr.containsKey(command)) { + Signal s = convcorr.ConvCorrCi(argList, command); + showSignal(s, false); + } else { + println("error: command not found."); + } + } catch (SignalDoesNotExist e) { + println("error: " + e.getMessage()); + } catch (IOException e) { + println("error: " + e.getMessage()); + } + return 0; + } + + public File getSignalDirectory() { + return signalDirectory; + } + + public void setSignalDirectory(File signalDirectory) { + this.signalDirectory = signalDirectory; + } +} diff --git a/asm/src/console/Commands.java b/asm/src/console/Commands.java new file mode 100644 index 0000000..ce76637 --- /dev/null +++ b/asm/src/console/Commands.java @@ -0,0 +1,61 @@ +package console; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import math.Calculations; +import math.ConvCorr; +import math.Transformations; +import signals.PlotCommands; +import signals.Sources; +import signals.Windowing; + +public class Commands { + + public static final Map commands = new HashMap() { + { + put("doff", new String[] { "", "" }); + put("don", new String[] { "", "" }); + put("list", new String[] { "", "" }); + put("boff", new String[] { "", "" }); + put("bon", new String[] { "", "" }); + put("exit", new String[] { "", "" }); + put("quit", new String[] { "", "" }); + } + }; + + public Commands() { + commands.putAll(Sources.functions); + commands.putAll(PlotCommands.plotcommands); + commands.putAll(Windowing.windows); + commands.putAll(Calculations.calculations); + commands.putAll(Transformations.transformations); + commands.putAll(ConvCorr.convcorr); + } + + public List getCommand(String command) { + List matches = new ArrayList(); + for (String cmd : commands.keySet()) { + if (cmd.startsWith(command)) + matches.add(cmd); + } + return matches; + } + + public List getAllCommands() { + List cmds = new ArrayList(commands.keySet()); + Collections.sort(cmds); + return cmds; + } + + public String getHelp(String command) { + if (commands.containsKey(command)) + return commands.get(command)[1]; + else + return null; + } + +} diff --git a/asm/src/console/Console.java b/asm/src/console/Console.java new file mode 100644 index 0000000..236a55f --- /dev/null +++ b/asm/src/console/Console.java @@ -0,0 +1,112 @@ +package console; + +import java.util.LinkedHashMap; +import java.util.Map; + +import dialogs.CalculationDialog; +import dialogs.OpenSignalDialog; +import dialogs.OperationsDialog; +import dialogs.SourceDialog; +import dialogs.TransformationsDialog; +import dialogs.WindowingDialog; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import signals.Signal; + +public class Console { + private final MenuBar menuBar; + private final TextArea consoleText; + private final TextField consoleInput; + private final CommandLineParser parser; + private final Map signals; + private final Stage stage; + + public Console(VBox v, Stage stage) { + this.stage = stage; + menuBar = new MenuBar(); + consoleText = new TextArea(); + consoleInput = new TextField(); + signals = new LinkedHashMap(); + parser = new CommandLineParser(signals, this); + + + Menu menuFile = new Menu("File"); + MenuItem menuItemOpen = new MenuItem("Open"); + MenuItem menuItemExit = new MenuItem("Exit"); + menuFile.getItems().add(menuItemOpen); + menuFile.getItems().add(menuItemExit); + + menuItemOpen.setOnAction(e -> { + new OpenSignalDialog(parser); + }); + menuItemExit.setOnAction(e -> { + System.exit(0); + }); + + Menu menuCommands = new Menu("Commands"); + MenuItem menuSources = new MenuItem("Sources"); + MenuItem menuWindowing = new MenuItem("Windowing"); + MenuItem menuCalculations = new MenuItem("Math operations"); + MenuItem menuTransformations = new MenuItem("Transformations"); + MenuItem menuOtherOperations = new MenuItem("Other operations"); + menuCommands.getItems().add(menuSources); + menuCommands.getItems().add(menuWindowing); + menuCommands.getItems().add(menuCalculations); + menuCommands.getItems().add(menuTransformations); + menuCommands.getItems().add(menuOtherOperations); + + menuSources.setOnAction(e -> { + new SourceDialog(parser); + }); + menuWindowing.setOnAction(e -> { + new WindowingDialog(parser); + }); + menuCalculations.setOnAction(e -> { + new CalculationDialog(parser, signals); + }); + menuTransformations.setOnAction(e -> { + new TransformationsDialog(parser, signals); + }); + menuOtherOperations.setOnAction(e -> { + new OperationsDialog(parser, signals); + }); + + menuBar.getMenus().add(menuFile); + menuBar.getMenus().add(menuCommands); + + + consoleText.setEditable(false); + // System.out.printf("max h %f\n",consoleText.getMaxHeight()); + consoleInput.setPromptText("Enter command here"); + + consoleInput.setOnAction(e -> { + String inputText = consoleInput.getText(); + //consoleText.appendText("> " + inputText + "\n"); + parser.parseCommand(inputText); + consoleInput.clear(); + // Put focus back to console + stage.requestFocus(); + }); + + v.getChildren().add(menuBar); + v.getChildren().add(consoleText); + v.getChildren().add(consoleInput); + } + + public void print(String message) { + consoleText.appendText(message); + } + + public void println(String message) { + consoleText.appendText(message + "\n"); + } + + public void show() { + stage.show(); + } +} diff --git a/asm/src/dialogs/CalculationDialog.java b/asm/src/dialogs/CalculationDialog.java new file mode 100644 index 0000000..a573dbe --- /dev/null +++ b/asm/src/dialogs/CalculationDialog.java @@ -0,0 +1,251 @@ +package dialogs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import math.Calculations; +import signals.Signal; +import signals.Sources; +import signals.Windowing; + +public class CalculationDialog { + + private final Label input2Label; + private final ComboBox input2Signals = new ComboBox(); + private final Label valueLabel; + private final TextField valueText; + private final Label value2Label; + private final TextField value2Text; + private final Label value3Label; + private final TextField value3Text; + private final Label valueRealLabel; + private final TextField valueRealText; + private final Label valueImagLabel; + private final TextField valueImagText; + private final Label outputSignalLabel; + private final TextField outputSignalText; + + // one input, same output + private static final List oneInputSameOutput = new ArrayList() { + { + add("clear"); + } + }; + // one input, two values, same output + private static final List oneInputTwoValuesSameOutput = new ArrayList() { + { + add("assign"); + } + }; + // one input, one output + private static final List oneInputOneOutput = new ArrayList() { + { + add("cabs"); + add("conjugate"); + add("cosine"); + add("copy"); + add("epow"); + add("inv"); + add("ln"); + add("log"); + add("sine"); + add("tenpow"); + add("zeropad"); + } + }; + + // one input, one value, one output + private static final List oneInputOneValueOneOutput = new ArrayList() { + { + add("cadd"); + add("cdivide"); + add("cmultiply"); + add("rotate"); + add("shift"); + } + }; + // two inputs, one output + private static final List twoInputsOneOutput = new ArrayList() { + { + add("absolute"); + add("add"); + add("divide"); + add("maximum"); + add("minimum"); + add("subtract"); + } + }; + + // two inputs, one value, one output + private static final List twoInputsOneValueOneOutput = new ArrayList() { + { + add("multiply"); + } + }; + + public CalculationDialog(CommandLineParser parser, Map signals) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Basic operations"); + dialog.setResizable(true); + + Label functionLabel = new Label("Operation:"); + ComboBox functions = new ComboBox(); + List functionList = new ArrayList(Calculations.calculations.keySet()); // set -> list + Collections.sort(functionList); + for (String s : functionList) { + functions.getItems().add(s); + } + functions.getSelectionModel().select("multiply"); + + Label inputLabel = new Label("input signal:"); + ComboBox inputSignals = new ComboBox(); + + List signalList = new ArrayList(signals.keySet()); // set -> list + Collections.sort(signalList); + for (String s : signalList) { + inputSignals.getItems().add(s); + } + + input2Label = new Label("input signal:"); + for (String s : signalList) { + input2Signals.getItems().add(s); + } + + valueLabel = new Label("constant:"); + valueText = new TextField(); + valueText.setPromptText("0"); + + value2Label = new Label("right:"); + value2Text = new TextField(); + value2Text.setPromptText(""); + + value3Label = new Label("attenuation:"); + value3Text = new TextField(); + value3Text.setPromptText("50.0"); + + valueRealLabel = new Label("real value:"); + valueRealText = new TextField(); + valueRealText.setPromptText("1"); + + valueImagLabel = new Label("imag value:"); + valueImagText = new TextField(); + valueImagText.setPromptText("1"); + + outputSignalLabel = new Label("output signal:"); + outputSignalText = new TextField(); + outputSignalText.setPromptText("b"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + grid.setMinHeight(250); + + grid.add(functionLabel, 0, 0); + grid.add(functions, 1, 0); + grid.add(inputLabel, 0, 1); + grid.add(inputSignals, 1, 1); + updateGrid(grid, (String) functions.getValue()); + dialog.getDialogPane().setContent(grid); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + functions.setOnAction(e -> { + grid.getChildren().removeIf(node -> GridPane.getRowIndex(node) > 1); + updateGrid(grid, (String) functions.getValue()); + outputSignalText.setPromptText((String) functions.getValue()); + }); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + String functionType = (String) functions.getValue(); + List l = new ArrayList(); + l.add(functionType); + l.add((String) inputSignals.getValue()); + if (oneInputOneValueOneOutput.contains(functionType)) { + l.add(valueText.getText()); + } + if (oneInputTwoValuesSameOutput.contains(functionType)) { + l.add(valueRealText.getText()); + l.add(valueImagText.getText()); + } + if (functionType.equals("clip")) { + l.add(valueText.getText()); + l.add(value2Text.getText()); + l.add(value3Text.getText()); + } + if (twoInputsOneOutput.contains(functionType) || + twoInputsOneValueOneOutput.contains(functionType)) { + l.add((String) input2Signals.getValue()); + } + if (twoInputsOneValueOneOutput.contains(functionType)) { + l.add(valueText.getText()); + } + if (!oneInputSameOutput.contains(functionType) && !oneInputTwoValuesSameOutput.contains(functionType)) { + l.add(outputSignalText.getText()); + } + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + + private void updateGrid(GridPane grid, String func) { + int r = 2; + if (oneInputOneValueOneOutput.contains(func)) { + grid.add(valueLabel, 0, r); + grid.add(valueText, 1, r++); + valueLabel.setText("constant:"); + if (func.equals("cadd")) + valueText.setPromptText("0"); + else + valueText.setPromptText("1"); + } + if (func.equals("clip")) { + valueLabel.setText("left:"); + grid.add(valueLabel, 0, r); + grid.add(valueText, 1, r++); + valueText.setPromptText("0"); + grid.add(value2Label, 0, r); + grid.add(value2Text, 1, r++); + grid.add(value3Label, 0, r); + grid.add(value3Text, 1, r++); + } + if (oneInputTwoValuesSameOutput.contains(func)) { + grid.add(valueRealLabel, 0, r); + grid.add(valueRealText, 1, r++); + grid.add(valueImagLabel, 0, r); + grid.add(valueImagText, 1, r++); + } + if (twoInputsOneOutput.contains(func) || + twoInputsOneValueOneOutput.contains(func)) { + grid.add(input2Label, 0, r); + grid.add(input2Signals, 1, r++); + } + if (twoInputsOneValueOneOutput.contains(func)) { + grid.add(valueLabel, 0, r); + grid.add(valueText, 1, r++); + valueText.setPromptText("1"); + } + if (!oneInputSameOutput.contains(func) && !oneInputTwoValuesSameOutput.contains(func)) { + grid.add(outputSignalLabel, 0, r); + grid.add(outputSignalText, 1, r++); + } + } +} diff --git a/asm/src/dialogs/OpenSignalDialog.java b/asm/src/dialogs/OpenSignalDialog.java new file mode 100644 index 0000000..9fb288b --- /dev/null +++ b/asm/src/dialogs/OpenSignalDialog.java @@ -0,0 +1,89 @@ +package dialogs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import console.CommandLineParser; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.stage.FileChooser; +import javafx.stage.Stage; + +public class OpenSignalDialog { + + private final Label inputFileLabel; + private final TextField inputFileText; + private final Label signalNameLabel; + private final TextField signalNameText; + private final Button browseButton = new Button("Browse"); + private final Stage stage = new Stage(); + private final FileChooser fileChooser = new FileChooser(); + + public OpenSignalDialog(CommandLineParser parser) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Open signal"); + dialog.setResizable(true); + + inputFileLabel = new Label("input file:"); + inputFileText = new TextField(); + inputFileText.setPromptText(""); + + signalNameLabel = new Label("signal name:"); + signalNameText = new TextField(); + signalNameText.setPromptText(""); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + grid.setMinHeight(250); + + grid.add(inputFileLabel, 0, 0); + grid.add(inputFileText, 1, 0); + grid.add(browseButton, 2, 0); + grid.add(signalNameLabel, 0, 1); + grid.add(signalNameText, 1, 1); + dialog.getDialogPane().setContent(grid); + + fileChooser.setTitle("Open Signal File"); + fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("ASM", "*.asm"), + new FileChooser.ExtensionFilter("All files", "*.*")); + + browseButton.setOnAction(event -> { + fileChooser.setInitialDirectory(parser.getSignalDirectory()); + File inputSignalFile = fileChooser.showOpenDialog(stage); + if (inputSignalFile != null) { + inputFileText.setText(inputSignalFile.getAbsolutePath()); + File signalDir = inputSignalFile.getParentFile(); + if (signalDir != null) + parser.setSignalDirectory(signalDir); + } + }); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + List l = new ArrayList(); + l.add("readf"); + l.add(inputFileText.getText()); + l.add(signalNameText.getText()); + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + +} diff --git a/asm/src/dialogs/OperationsDialog.java b/asm/src/dialogs/OperationsDialog.java new file mode 100644 index 0000000..8fd406a --- /dev/null +++ b/asm/src/dialogs/OperationsDialog.java @@ -0,0 +1,127 @@ +package dialogs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import math.ConvCorr; +import math.Transformations; +import signals.Signal; + +public class OperationsDialog { + + private final Label input2Label; + private final ComboBox input2Signals = new ComboBox(); + private final Label outputSignalLabel; + private final TextField outputSignalText; + private final Label windowTypeLabel; + private final ComboBox windowType; + + public OperationsDialog(CommandLineParser parser, Map signals) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Operations"); + dialog.setResizable(true); + + Label functionLabel = new Label("Operation:"); + ComboBox functions = new ComboBox(); + List functionList = new ArrayList(ConvCorr.convcorr.keySet()); // set -> list + Collections.sort(functionList); + for (String s : functionList) { + functions.getItems().add(s); + } + functions.getSelectionModel().select("correlation"); + + Label inputLabel = new Label("input signal:"); + ComboBox inputSignals = new ComboBox(); + + List signalList = new ArrayList(signals.keySet()); // set -> list + Collections.sort(signalList); + for (String s : signalList) { + inputSignals.getItems().add(s); + } + + input2Label = new Label("input signal:"); + for (String s : signalList) { + input2Signals.getItems().add(s); + } + + outputSignalLabel = new Label("output signal:"); + outputSignalText = new TextField(); + outputSignalText.setPromptText("b"); + + windowTypeLabel = new Label("window type:"); + windowType = new ComboBox(); + windowType.getItems().add("block"); + windowType.getItems().add("hanning"); + windowType.getItems().add("hamming"); + windowType.getItems().add("gauss"); + windowType.getItems().add("blackman"); + windowType.getItems().add("kaiser"); + windowType.getItems().add("triangle"); + windowType.getSelectionModel().select("block"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + grid.setMinHeight(250); + + grid.add(functionLabel, 0, 0); + grid.add(functions, 1, 0); + grid.add(inputLabel, 0, 1); + grid.add(inputSignals, 1, 1); + updateGrid(grid, (String) functions.getValue()); + dialog.getDialogPane().setContent(grid); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + functions.setOnAction(e -> { + grid.getChildren().removeIf(node -> GridPane.getRowIndex(node) > 1); + updateGrid(grid, (String) functions.getValue()); + outputSignalText.setPromptText((String) functions.getValue()); + }); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + String functionType = (String) functions.getValue(); + List l = new ArrayList(); + l.add(functionType); + l.add((String) inputSignals.getValue()); + l.add((String) input2Signals.getValue()); + l.add(outputSignalText.getText()); + l.add(Integer.toString(windowType.getSelectionModel().getSelectedIndex())); + + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + + private void updateGrid(GridPane grid, String func) { + int r = 2; + grid.add(input2Label, 0, r); + grid.add(input2Signals, 1, r++); + + grid.add(outputSignalLabel, 0, r); + grid.add(outputSignalText, 1, r++); + + grid.add(windowTypeLabel, 0, r); + grid.add(windowType, 1, r++); + + } +} \ No newline at end of file diff --git a/asm/src/dialogs/SaveSignalDialog.java b/asm/src/dialogs/SaveSignalDialog.java new file mode 100644 index 0000000..cb93be7 --- /dev/null +++ b/asm/src/dialogs/SaveSignalDialog.java @@ -0,0 +1,124 @@ +package dialogs; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import signals.Signal; + +public class SaveSignalDialog { + + private final Label outputFileLabel; + private final TextField outputFileText; + private final Label userTextLabel; + private final TextField userText; + private final Label descriptionLabel; + private final TextField descriptionText; + private final Button browseButton = new Button("Browse"); + private final Stage stage = new Stage(); + private final FileChooser fileChooser = new FileChooser(); + + public SaveSignalDialog(CommandLineParser parser, Map signals, String signalName) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Save signal"); + dialog.setResizable(true); + + Label inputLabel = new Label("signal:"); + ComboBox inputSignals = new ComboBox(); + + List signalList = new ArrayList(signals.keySet()); // set -> list + Collections.sort(signalList); + for (String s : signalList) { + inputSignals.getItems().add(s); + } + if (signalName != null) + inputSignals.getSelectionModel().select(signalName); + + outputFileLabel = new Label("output file:"); + outputFileText = new TextField(); + if (signalName != null) + outputFileText.setText(signalName + ".asm"); + else + outputFileText.setPromptText("a.asm"); + + userTextLabel = new Label("user text:"); + userText = new TextField(); + userText.setPromptText("DataUserText"); + + descriptionLabel = new Label("description:"); + descriptionText = new TextField(); + descriptionText.setPromptText("description"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + grid.setMinHeight(250); + + grid.add(inputLabel, 0, 0); + grid.add(inputSignals, 1, 0); + grid.add(outputFileLabel, 0, 1); + grid.add(outputFileText, 1, 1); + grid.add(browseButton, 2, 1); + grid.add(userTextLabel, 0, 2); + grid.add(userText, 1, 2); + grid.add(descriptionLabel, 0, 3); + grid.add(descriptionText, 1, 3); + dialog.getDialogPane().setContent(grid); + + fileChooser.setTitle("Save Signal File"); + fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("ASM", "*.asm"), + new FileChooser.ExtensionFilter("All files", "*.*")); + + browseButton.setOnAction(event -> { + fileChooser.setInitialDirectory(parser.getSignalDirectory()); + File outputSignalFile = fileChooser.showSaveDialog(stage); + if (outputSignalFile != null) { + outputFileText.setText(outputSignalFile.getAbsolutePath()); + File signalDir = outputSignalFile.getParentFile(); + if (signalDir != null) + parser.setSignalDirectory(signalDir); + } + }); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + inputSignals.setOnAction(e -> { + outputFileText.setText(inputSignals.getValue() + ".asm"); + }); + + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + List l = new ArrayList(); + l.add("writef"); + l.add((String) inputSignals.getValue()); + l.add(outputFileText.getText()); + l.add(userText.getText()); + l.add(descriptionText.getText()); + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + +} \ No newline at end of file diff --git a/asm/src/dialogs/SourceDialog.java b/asm/src/dialogs/SourceDialog.java new file mode 100644 index 0000000..b4d55a5 --- /dev/null +++ b/asm/src/dialogs/SourceDialog.java @@ -0,0 +1,226 @@ +package dialogs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import signals.Sources; + +public class SourceDialog { + + private final Label offsetLabel; + private final TextField offsetText; + private final Label amplitudeLabel; + private final TextField amplitudeText; + private final Label frequencyLabel; + private final TextField frequencyText; + private final Label phaseLabel; + private final TextField phaseText; + private final Label deltatLabel; + private final TextField deltatText; + private final Label t63Label; + private final TextField t63Text; + private final Label tDelayLabel; + private final TextField tDelayText; + private final Label dutyCycleLabel; + private final TextField dutyCycleText; + private final Label datatypeLabel; + private final ComboBox datatype; + private final Label nrOfElementsLabel; + private final TextField nrOfElementsText; + private final Label samplerateLabel; + private final TextField samplerateText; + private final Label seedLabel; + private final TextField seedText; + + public SourceDialog(CommandLineParser parser) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Sources"); + dialog.setResizable(true); + + Label functionLabel = new Label("function:"); + ComboBox functions = new ComboBox(); + List functionList = new ArrayList(Sources.functions.keySet()); // set -> list + Collections.sort(functionList); + for (String s : functionList) { + functions.getItems().add(s.substring(1)); + } + functions.getSelectionModel().select("sine"); + + Label nameLabel = new Label("Signal name:"); + TextField nameText = new TextField(); + nameText.setPromptText((String) functions.getValue()); + + offsetLabel = new Label("Offset:"); + offsetText = new TextField(); + offsetText.setPromptText("0"); + + amplitudeLabel = new Label("Amplitude:"); + amplitudeText = new TextField(); + amplitudeText.setPromptText("100"); + + frequencyLabel = new Label("Frequency (Hz):"); + frequencyText = new TextField(); + frequencyText.setPromptText("100"); + + phaseLabel = new Label("Phase (rad):"); + phaseText = new TextField(); + phaseText.setPromptText("0"); + + deltatLabel = new Label("Delta-t (millisec):"); + deltatText = new TextField(); + deltatText.setPromptText("0"); + + t63Label = new Label("t 63.2% (millisec):"); + t63Text = new TextField(); + t63Text.setPromptText("10.0"); + + tDelayLabel = new Label("t-delay (ms):"); + tDelayText = new TextField(); + tDelayText.setPromptText("0.0"); + + dutyCycleLabel = new Label("Duty-cycle <0% .. 100%>:"); + dutyCycleText = new TextField(); + dutyCycleText.setPromptText("50.0"); + + datatypeLabel = new Label("Data type:"); + datatype = new ComboBox(); + datatype.getItems().add("real"); + datatype.getItems().add("imaginary"); + datatype.getItems().add("complex"); + datatype.getSelectionModel().select("real"); + + nrOfElementsLabel = new Label("Nr of elements (2^n):"); + nrOfElementsText = new TextField(); + nrOfElementsText.setPromptText("9"); + + samplerateLabel = new Label("Sample rate (10 Hz):"); + samplerateText = new TextField(); + samplerateText.setPromptText("5120"); + + seedLabel = new Label("Seed:"); + seedText = new TextField(); + seedText.setPromptText("1"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + + grid.add(functionLabel, 0, 0); + grid.add(functions, 1, 0); + grid.add(nameLabel, 0, 1); + grid.add(nameText, 1, 1); + updateGrid(grid, (String) functions.getValue()); + dialog.getDialogPane().setContent(grid); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + functions.setOnAction(e -> { + grid.getChildren().removeIf(node -> GridPane.getRowIndex(node) > 1); + nameText.setPromptText((String) functions.getValue()); + updateGrid(grid, (String) functions.getValue()); + }); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + String functionType = (String) functions.getValue(); + List l = new ArrayList(); + l.add("f" + functionType); + l.add(nameText.getText()); + if (functionType.equals("cosine") || functionType.equals("ramp") || functionType.startsWith("sin") + || functionType.equals("square") || functionType.equals("step") + || functionType.equals("triangle")) { + l.add(offsetText.getText()); + } + l.add(amplitudeText.getText()); + if (functionType.equals("delta")) { + l.add(deltatText.getText()); + } + if (functionType.equals("exp")) { + l.add(t63Text.getText()); + } + if (functionType.equals("step")) { + l.add(tDelayText.getText()); + } + if (functionType.equals("cosine") || functionType.startsWith("sin") || functionType.equals("square") + || functionType.equals("triangle")) { + l.add(frequencyText.getText()); + } + if (functionType.equals("cosine") || functionType.equals("sine") || functionType.equals("triangle")) { + l.add(phaseText.getText()); + } + if (functionType.equals("square")) { + l.add(dutyCycleText.getText()); + } + l.add(Integer.toString(datatype.getSelectionModel().getSelectedIndex())); + if (functionType.equals("noise")) { + l.add(seedText.getText()); + } + l.add(nrOfElementsText.getText()); + l.add(samplerateText.getText()); + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + + private void updateGrid(GridPane grid, String func) { + int r = 2; + if (func.equals("cosine") || func.equals("ramp") || func.startsWith("sin") || func.equals("square") + || func.equals("step") || func.equals("triangle")) { + grid.add(offsetLabel, 0, r); + grid.add(offsetText, 1, r++); + } + grid.add(amplitudeLabel, 0, r); + grid.add(amplitudeText, 1, r++); + if (func.equals("delta")) { + grid.add(deltatLabel, 0, r); + grid.add(deltatText, 1, r++); + } + if (func.equals("exp")) { + grid.add(t63Label, 0, r); + grid.add(t63Text, 1, r++); + } + if (func.equals("step")) { + grid.add(tDelayLabel, 0, r); + grid.add(tDelayText, 1, r++); + } + if (func.equals("cosine") || func.startsWith("sin") || func.equals("square") || func.equals("triangle")) { + grid.add(frequencyLabel, 0, r); + grid.add(frequencyText, 1, r++); + } + if (func.equals("cosine") || func.equals("sine") || func.equals("triangle")) { + grid.add(phaseLabel, 0, r); + grid.add(phaseText, 1, r++); + } + if (func.equals("square")) { + grid.add(dutyCycleLabel, 0, r); + grid.add(dutyCycleText, 1, r++); + } + grid.add(datatypeLabel, 0, r); + grid.add(datatype, 1, r++); + if (func.equals("noise")) { + grid.add(seedLabel, 0, r); + grid.add(seedText, 1, r++); + } + grid.add(nrOfElementsLabel, 0, r); + grid.add(nrOfElementsText, 1, r++); + grid.add(samplerateLabel, 0, r); + grid.add(samplerateText, 1, r++); + } +} diff --git a/asm/src/dialogs/TransformationsDialog.java b/asm/src/dialogs/TransformationsDialog.java new file mode 100644 index 0000000..0a54392 --- /dev/null +++ b/asm/src/dialogs/TransformationsDialog.java @@ -0,0 +1,190 @@ +package dialogs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import math.Transformations; +import signals.Signal; + +public class TransformationsDialog { + + private final Label valueLabel; + private final TextField valueText; + private final Label value2Label; + private final TextField value2Text; + private final Label value3Label; + private final TextField value3Text; + private final Label outputSignalLabel; + private final TextField outputSignalText; + private final Label windowTypeLabel; + private final ComboBox windowType; + private final Label bucketsLabel; + private final ComboBox buckets; + + public TransformationsDialog(CommandLineParser parser, Map signals) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Transformations"); + dialog.setResizable(true); + + Label functionLabel = new Label("Transformation:"); + ComboBox functions = new ComboBox(); + List functionList = new ArrayList(Transformations.transformations.keySet()); // set -> list + Collections.sort(functionList); + for (String s : functionList) { + functions.getItems().add(s); + } + functions.getSelectionModel().select("fft"); + + Label inputLabel = new Label("input signal:"); + ComboBox inputSignals = new ComboBox(); + + List signalList = new ArrayList(signals.keySet()); // set -> list + Collections.sort(signalList); + for (String s : signalList) { + inputSignals.getItems().add(s); + } + + valueLabel = new Label("constant:"); + valueText = new TextField(); + valueText.setPromptText("0"); + + value2Label = new Label("right:"); + value2Text = new TextField(); + value2Text.setPromptText(""); + + value3Label = new Label("attenuation:"); + value3Text = new TextField(); + value3Text.setPromptText("50.0"); + + outputSignalLabel = new Label("output signal:"); + outputSignalText = new TextField(); + outputSignalText.setPromptText("b"); + + windowTypeLabel = new Label("window type:"); + windowType = new ComboBox(); + windowType.getItems().add("block"); + windowType.getItems().add("hanning"); + windowType.getItems().add("hamming"); + windowType.getItems().add("gauss"); + windowType.getItems().add("blackman"); + windowType.getItems().add("kaiser"); + windowType.getItems().add("triangle"); + windowType.getSelectionModel().select("hanning"); + + bucketsLabel = new Label("buckets:"); + buckets = new ComboBox(); + buckets.getItems().add("7"); + buckets.getItems().add("8"); + buckets.getItems().add("9"); + buckets.getItems().add("10"); + buckets.getItems().add("11"); + buckets.getItems().add("12"); + buckets.getSelectionModel().select("9"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + grid.setMinHeight(250); + + grid.add(functionLabel, 0, 0); + grid.add(functions, 1, 0); + grid.add(inputLabel, 0, 1); + grid.add(inputSignals, 1, 1); + updateGrid(grid, (String) functions.getValue()); + dialog.getDialogPane().setContent(grid); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + functions.setOnAction(e -> { + grid.getChildren().removeIf(node -> GridPane.getRowIndex(node) > 1); + updateGrid(grid, (String) functions.getValue()); + outputSignalText.setPromptText((String) functions.getValue()); + }); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + String functionType = (String) functions.getValue(); + List l = new ArrayList(); + l.add(functionType); + l.add((String) inputSignals.getValue()); + l.add(outputSignalText.getText()); + if (!functionType.equals("ifft")) { + l.add(valueText.getText()); + } + if (functionType.equals("fft")) { + l.add(Integer.toString(windowType.getSelectionModel().getSelectedIndex())); + + } + if (functionType.equals("fft") || functionType.equals("magnitude") || functionType.equals("phase")) { + l.add(value2Text.getText()); + } + if (functionType.equals("fft") || functionType.equals("magnitude")) { + l.add(value3Text.getText()); + } + if (functionType.equals("histogram")) { + l.add(buckets.getValue()); + } + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + + private void updateGrid(GridPane grid, String func) { + int r = 2; + grid.add(outputSignalLabel, 0, r); + grid.add(outputSignalText, 1, r++); + if (func.equals("fft")) { + valueLabel.setText("length:"); + grid.add(valueLabel, 0, r); + grid.add(valueText, 1, r++); + valueText.setPromptText("9"); + + grid.add(windowTypeLabel, 0, r); + grid.add(windowType, 1, r++); + + value3Label.setText("average type:"); + grid.add(value3Label, 0, r); + grid.add(value3Text, 1, r++); + value3Text.setPromptText("0"); + } + if (func.equals("magnitude") || func.equals("phase")) { + valueLabel.setText("channel:"); + grid.add(valueLabel, 0, r); + grid.add(valueText, 1, r++); + valueText.setPromptText("0"); + + value2Label.setText("average type:"); + grid.add(value2Label, 0, r); + grid.add(value2Text, 1, r++); + value2Text.setPromptText("0"); + } + if (func.equals("magnitude")) { + value3Label.setText("log:"); + grid.add(value3Label, 0, r); + grid.add(value3Text, 1, r++); + value3Text.setPromptText("0"); + } + if (func.equals("histogram")) { + grid.add(bucketsLabel, 0, r); + grid.add(buckets, 1, r++); + } + } +} \ No newline at end of file diff --git a/asm/src/dialogs/WindowingDialog.java b/asm/src/dialogs/WindowingDialog.java new file mode 100644 index 0000000..9c4b101 --- /dev/null +++ b/asm/src/dialogs/WindowingDialog.java @@ -0,0 +1,97 @@ +package dialogs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import console.CommandLineParser; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import signals.Windowing; + +public class WindowingDialog { + + private final Label nrOfElementsLabel; + private final TextField nrOfElementsText; + private final Label samplerateLabel; + private final TextField samplerateText; + + public WindowingDialog(CommandLineParser parser) { + Dialog> dialog = new Dialog>(); + dialog.setTitle("Windows"); + dialog.setResizable(true); + + Label functionLabel = new Label("window:"); + ComboBox functions = new ComboBox(); + List windowList = new ArrayList(Windowing.windows.keySet()); // set -> list + Collections.sort(windowList); + for (String s : windowList) { + functions.getItems().add(s.substring(1)); + } + functions.getSelectionModel().select("block"); + + Label nameLabel = new Label("Signal name:"); + TextField nameText = new TextField(); + nameText.setPromptText((String) functions.getValue()); + + nrOfElementsLabel = new Label("Nr of elements (2^n):"); + nrOfElementsText = new TextField(); + nrOfElementsText.setPromptText("9"); + + samplerateLabel = new Label("Sample rate (10 Hz):"); + samplerateText = new TextField(); + samplerateText.setPromptText("5120"); + + GridPane grid = new GridPane(); + grid.setHgap(10.0); + grid.setVgap(10.0); + + grid.add(functionLabel, 0, 0); + grid.add(functions, 1, 0); + grid.add(nameLabel, 0, 1); + grid.add(nameText, 1, 1); + updateGrid(grid, (String) functions.getValue()); + dialog.getDialogPane().setContent(grid); + + ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeCancel); + ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); + + functions.setOnAction(e -> { + //grid.getChildren().removeIf(node -> GridPane.getRowIndex(node) > 1); + //updateGrid(grid, (String) functions.getValue()); + nameText.setPromptText((String) functions.getValue()); + }); + + dialog.setResultConverter(button -> { + if (button == buttonTypeOk) { + String functionType = (String) functions.getValue(); + List l = new ArrayList(); + l.add("w" + functionType); + l.add(nameText.getText()); + l.add(nrOfElementsText.getText()); + l.add(samplerateText.getText()); + return l; + } + return null; + }); + dialog.showAndWait().ifPresent(result -> { + parser.parseCommand(result); + }); + ; + } + + private void updateGrid(GridPane grid, String func) { + int r = 2; + grid.add(nrOfElementsLabel, 0, r); + grid.add(nrOfElementsText, 1, r++); + grid.add(samplerateLabel, 0, r); + grid.add(samplerateText, 1, r++); + } +} diff --git a/asm/src/exceptions/SignalDoesNotExist.java b/asm/src/exceptions/SignalDoesNotExist.java new file mode 100644 index 0000000..d70662d --- /dev/null +++ b/asm/src/exceptions/SignalDoesNotExist.java @@ -0,0 +1,29 @@ +package exceptions; + +public class SignalDoesNotExist extends Exception { + + public SignalDoesNotExist() { + // TODO Auto-generated constructor stub + } + + public SignalDoesNotExist(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public SignalDoesNotExist(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + public SignalDoesNotExist(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public SignalDoesNotExist(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + +} diff --git a/asm/src/math/Calculations.java b/asm/src/math/Calculations.java new file mode 100644 index 0000000..465f77e --- /dev/null +++ b/asm/src/math/Calculations.java @@ -0,0 +1,869 @@ +package math; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import exceptions.SignalDoesNotExist; +import signals.Signal; +import signals.Sources; + +public class Calculations extends MathBase{ + public static final Map calculations = new HashMap() { + { + put("absolute", new String[]{"twoInputsOneOutputCi",""}); + put("add", new String[]{"twoInputsOneOutputCi",""}); + put("assign", new String[]{"assign",""}); + put("cabs", new String[]{"oneInputOneOutputCi",""}); + put("cadd", new String[]{"oneInputOneValueOneOutputCi",""}); + put("cdivide", new String[]{"oneInputOneValueOneOutputCi",""}); + put("clear", new String[]{"clear",""}); + put("clip", new String[]{"clip",""}); + put("cmultiply", new String[]{"oneInputOneValueOneOutputCi",""}); + put("conjugate", new String[]{"oneInputOneOutputCi",""}); + put("copy", new String[]{"oneInputOneOutputCi",""}); + put("cosine", new String[]{"oneInputOneOutputCi",""}); + put("divide", new String[]{"twoInputsOneOutputCi",""}); + put("epow", new String[]{"oneInputOneOutputCi",""}); + put("inv", new String[]{"oneInputOneOutputCi",""}); + put("ln", new String[]{"oneInputOneOutputCi",""}); + put("log", new String[]{"oneInputOneOutputCi",""}); + put("maximum", new String[]{"twoInputsOneOutputCi",""}); + put("minimum", new String[]{"twoInputsOneOutputCi",""}); + put("multiply", new String[]{"multiply",""}); + put("rotate", new String[]{"oneInputOneValueOneOutputCi",""}); + put("shift", new String[]{"oneInputOneValueOneOutputCi",""}); + put("sine", new String[]{"oneInputOneOutputCi",""}); + put("subtract", new String[]{"twoInputsOneOutputCi",""}); + put("tenpow", new String[]{"oneInputOneOutputCi",""}); + put("zeropad", new String[]{"oneInputOneOutputCi",""}); + } + }; + + public Calculations(Map signals, CommandLineParser cp) { + super(signals, cp); + } + + private void clear(Signal signal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + + for (int i = 0; i < length; i++) { + re[i] = im[i] = 0; + } + } + + public Signal clear(List arguments, String command) { + String signalname = cp.getString(arguments, "Signal", command); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + // TODO: Throw signal not found. + return null; + } + clear(signal); + return signal; + } + + private void assign(Signal signal, double realValue, double imagValue) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + + for (int i = 0; i < length; i++) { + re[i] = realValue; + im[i] = imagValue; + } + } + + public Signal assign(List arguments, String command) { + String signalname = cp.getString(arguments, "Signal", command); + double realValue = cp.getDouble(arguments, "Real part", Integer.MIN_VALUE, Integer.MAX_VALUE, 1.0); + double imagValue = cp.getDouble(arguments, "Imag part", Integer.MIN_VALUE, Integer.MAX_VALUE, 1.0); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + // TODO: Throw signal not found. + return null; + } + + if (signal.getDataType() == Signal.REAL) + imagValue = 0.0; + else if (signal.getDataType() == Signal.IMAG) + realValue = 0.0; + + assign(signal, realValue, imagValue); + return signal; + } + + public void multiply(Signal signal1, Signal signal2, double constant, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = (re1[i] * re2[i] - im1[i] * im2[i]) / constant; + im_out[i] = (re1[i] * im2[i] + im1[i] * re2[i]) / constant; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal multiply(List arguments, String command) throws SignalDoesNotExist { + String signalname1 = cp.getString(arguments, "Signal", "a"); + String signalname2 = cp.getString(arguments, "Signal", "b"); + double constant = cp.getDouble(arguments, "Constant", 1, Integer.MAX_VALUE, 1.0); + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal signal1 = signals.get(signalname1); /* Find the correct signal */ + if (signal1 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname1 + "\" does not exist."); + } + Signal signal2 = signals.get(signalname2); /* Find the correct signal */ + if (signal2 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname2 + "\" does not exist."); + } + if (signal1.getDataDomain() != signal2.getDataDomain()) { + return null; + } + if (signal1.getDataLength() != signal2.getDataLength() || signal1.getDataRecords() != signal2.getDataRecords() + || signal1.getDataChannels() != signal2.getDataChannels()) { + return null; + } + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + + setSignalValues(outputSignal, signal1); + if (signal1.getDataType() != signal2.getDataType()) { + outputSignal.setDataType(Signal.COMP); + } + + multiply(signal1, signal2, constant, outputSignal); + + return outputSignal; + } + + public void cabs(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.sqrt(Math.pow(re[i], 2.0) + Math.pow(im[i], 2.0)); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void conjugate(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i]; + im_out[i] = -im[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void cosine(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.cos(re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void epow(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.exp(re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void copy(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i]; + im_out[i] = im[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void inv(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = -re[i]; + im_out[i] = -im[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void ln(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.log(re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void log(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.log10(re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void sine(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.sin(re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void tenpow(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.pow(10.0, re[i]); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void zeropad(Signal signal, Signal outputSignal) { + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + if (length > Math.pow(2, Signal.MAX_N)) { + // TODO max length error + } + // TODO zeropad per record. + + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + double[] re_out = new double[2 * length]; + double[] im_out = new double[2 * length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i]; + im_out[i] = im[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + outputSignal.setDataLength((short) (2 * signal.getDataLength())); + } + + public Signal oneInputOneOutputCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (command.equals("zeropad") && signal.getDataDomain() != Signal.TIME) { + // TODO domain error + System.out.println("domain error"); + return null; + } + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + Method method = null; + String methodName = command; + try { + method = this.getClass().getMethod(methodName, Signal.class, Signal.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + method.invoke(this, signal, outputSignal); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return outputSignal; + } + + public void cadd(Signal signal, Signal outputSignal, double value) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i] + value; + im_out[i] = im[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void cdivide(Signal signal, Signal outputSignal, double value) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i] / value; + im_out[i] = im[i] / value; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void cmultiply(Signal signal, Signal outputSignal, double value) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re[i] * value; + im_out[i] = im[i] * value; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void rotate(Signal signal, Signal outputSignal, double value) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + int channelLength = signal.getDataRecords() * signal.getDataLength(); + int rotate = (int) value; + rotate = rotate%channelLength; + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + // Rotate per channel. + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + int chan_offset = channel * channelLength; + for (int i = 0; i < channelLength; i++) { + + if (rotate >= 0) { + if (i < rotate) { + re_out[i + chan_offset] = re[channelLength - rotate + i + chan_offset]; + im_out[i + chan_offset] = im[channelLength - rotate + i + chan_offset]; + } + if (i >= rotate) { + re_out[i + chan_offset] = re[i - rotate + chan_offset]; + im_out[i + chan_offset] = im[i - rotate + chan_offset]; + } + } + if (rotate < 0) { + if (i >= channelLength + rotate) { + re_out[i + chan_offset] = re[i - (channelLength + rotate) + chan_offset]; + im_out[i + chan_offset] = im[i - (channelLength + rotate) + chan_offset]; + } + if (i < channelLength + rotate) { + re_out[i + chan_offset] = re[i - rotate + chan_offset]; + im_out[i + chan_offset] = im[i - rotate + chan_offset]; + } + } + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void shift(Signal signal, Signal outputSignal, double value) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int length = signal.getDataChannels() * signal.getDataRecords() * signal.getDataLength(); + int channelLength = signal.getDataRecords() * signal.getDataLength(); + int shift = (int) value; + shift = shift%channelLength; + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + // Shift per channel. + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + int chan_offset = channel * channelLength; + for (int i = 0; i < channelLength; i++) { + + if (shift >= 0) { + if (i < shift) { + re_out[i + chan_offset] = 0; + im_out[i + chan_offset] = 0; + } + if (i >= shift) { + re_out[i + chan_offset] = re[i - shift + chan_offset]; + im_out[i + chan_offset] = im[i - shift + chan_offset]; + } + } + if (shift < 0) { + if (i >= channelLength + shift) { + re_out[i + chan_offset] = 0; + im_out[i + chan_offset] = 0; + } + if (i < channelLength + shift) { + re_out[i + chan_offset] = re[i - shift + chan_offset]; + im_out[i + chan_offset] = im[i - shift + chan_offset]; + } + } + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal oneInputOneValueOneOutputCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + double defaultValue; + if (command.equals("cadd")) + defaultValue = 0.0; + else + defaultValue = 1.0; + double minValue; + if (command.equals("cdivide")) + minValue = 1.0; + else + minValue = Integer.MIN_VALUE; + double value = cp.getDouble(arguments, "Constant", minValue, Integer.MAX_VALUE, defaultValue); + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + Method method = null; + String methodName = command; + try { + method = this.getClass().getMethod(methodName, Signal.class, Signal.class, double.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + method.invoke(this, signal, outputSignal, value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return outputSignal; + } + + public void clip(Signal signal, int left, int right, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int length = signal.getDataChannels() * signal.getDataRecords() * dataLength; + int channelLength = signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + // Clip per channel. + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + { + for (int record = 0; record < signal.getDataRecords(); record++) { + /* Bereken offset van betreffende record */ + int offset = (channel * signal.getDataRecords() + record) * dataLength; + + for (int i = 0; i < dataLength; i++) { + if ((i < left) || (i > right)) { + re_out[i + offset] = 0.0; + im_out[i + offset] = 0.0; + } else { + re_out[i + offset] = re[i + offset]; + im_out[i + offset] = im[i + offset]; + } + } + + } + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void clip(Signal signal, double leftfreq, double rightfreq, double attenuation, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int length = signal.getDataChannels() * signal.getDataRecords() * dataLength; + int channelLength = signal.getDataRecords() * signal.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + attenuation = Math.pow(10.0, attenuation / 10); + int left = (int) ((leftfreq / (10.0 * (double) signal.getDataSampleRate())) * (double) dataLength); + int right = (int) ((rightfreq / (10.0 * (double) signal.getDataSampleRate())) * (double) dataLength); + if (left < 0.0) + left = 0; + + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + + for (int record = 0; record < signal.getDataRecords(); record++) { + /* Bereken offset van betreffende record */ + int offset = (channel * signal.getDataRecords() + record) * dataLength; + for (int i = 0; i < dataLength; i++) { + if ((i < left) || ((i > right) && (i < (dataLength - right - 1))) + || (i > (dataLength - left - 1))) { + re_out[i + offset] = re[i + offset] / attenuation; + im_out[i + offset] = im[i + offset] / attenuation; + } else { + re_out[i + offset] = re[i + offset]; + im_out[i + offset] = im[i + offset]; + } + } + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal clip(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.TIME && signal.getDataDomain() != Signal.FREQ) { + // TODO domain error + System.out.println("domain error"); + return null; + } + int left=0, right=signal.getDataLength(); + double leftfreq=1.0, rightfreq=(signal.getDataSampleRate() / 2) * 10; + double attenuation=50.0; + if (signal.getDataDomain() == Signal.FREQ) { + double maxValue = (signal.getDataSampleRate() / 2) * 10; + leftfreq = cp.getDouble(arguments, "left (frequency)", 1.0, maxValue, 1.0); + rightfreq = cp.getDouble(arguments, "right (frequency)", leftfreq, maxValue, maxValue); + attenuation = cp.getDouble(arguments, "attenuation", 0.0, 100.0, 50.0); + } else { + int maxValue = signal.getDataLength(); + left = cp.getInt(arguments, "left (element)", 0, maxValue, 0); + right = cp.getInt(arguments, "right (element)", 0, maxValue, 0); + // The GUI dialog passes attenuation. Command line not. + if (arguments.size()>1) { + // dummy read. + attenuation = cp.getDouble(arguments, "attenuation", 0.0, 100.0, 50.0); + } + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + if (signal.getDataDomain() == Signal.FREQ) { + clip(signal, leftfreq, rightfreq, attenuation, outputSignal); + } else { + clip(signal, left, right, outputSignal); + } + return outputSignal; + } + + public void abs(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.sqrt(Math.pow(re1[i] - re2[i], 2.0) + Math.pow(im1[i] - im2[i], 2.0)); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void add(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re1[i] + re2[i]; + im_out[i] = im1[i] + im2[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void divide(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = Math.sqrt(Math.pow(re1[i], 2.0) + Math.pow(im1[i], 2.0)) + / (1.0 + Math.sqrt(Math.pow(re2[i], 2.0) + Math.pow(im2[i], 2.0))); + im_out[i] = 0.0; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void maximum(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + if ((Math.pow(re1[i], 2.0) + Math.pow(im1[i], 2.0)) >= (Math.pow(re2[i], 2.0) + Math.pow(im2[i], 2.0))) { + re_out[i] = re1[i]; + im_out[i] = im1[i]; + } else { + re_out[i] = re2[i]; + im_out[i] = im2[i]; + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void minimum(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + if ((Math.pow(re1[i], 2.0) + Math.pow(im1[i], 2.0)) < (Math.pow(re2[i], 2.0) + Math.pow(im2[i], 2.0))) { + re_out[i] = re1[i]; + im_out[i] = im1[i]; + } else { + re_out[i] = re2[i]; + im_out[i] = im2[i]; + } + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public void subtract(Signal signal1, Signal signal2, Signal outputSignal) { + double[] re1 = signal1.getRealData(); + double[] im1 = signal1.getImagData(); + double[] re2 = signal2.getRealData(); + double[] im2 = signal2.getImagData(); + int length = signal1.getDataChannels() * signal1.getDataRecords() * signal1.getDataLength(); + double[] re_out = new double[length]; + double[] im_out = new double[length]; + + for (int i = 0; i < length; i++) { + re_out[i] = re1[i] - re2[i]; + im_out[i] = im1[i] - im2[i]; + } + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal twoInputsOneOutputCi(List arguments, String command) throws SignalDoesNotExist { + String signalname1 = cp.getString(arguments, "Signal", "a"); + String signalname2 = cp.getString(arguments, "Signal", "b"); + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal signal1 = signals.get(signalname1); /* Find the correct signal */ + if (signal1 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname1 + "\" does not exist."); + } + Signal signal2 = signals.get(signalname2); /* Find the correct signal */ + if (signal2 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname2 + "\" does not exist."); + } + if (signal1.getDataDomain() != signal2.getDataDomain()) { + return null; + } + if (signal1.getDataLength() != signal2.getDataLength() || signal1.getDataRecords() != signal2.getDataRecords() + || signal1.getDataChannels() != signal2.getDataChannels()) { + return null; + } + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + + setSignalValues(outputSignal, signal1); + if (signal1.getDataType() != signal2.getDataType()) { + outputSignal.setDataType(Signal.COMP); + } + + Method method = null; + String methodName = command; + try { + method = this.getClass().getMethod(methodName, Signal.class, Signal.class, Signal.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + method.invoke(this, signal1, signal2, outputSignal); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return outputSignal; + } + + public Signal CalculateCi(List arguments, String command) throws SignalDoesNotExist { + Signal outputSignal = null; + + Method method = null; + String methodName = calculations.get(command)[0]; + try { + method = this.getClass().getMethod(methodName, List.class, String.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + outputSignal = (Signal) method.invoke(this, arguments, command); + } catch (IllegalAccessException | IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof SignalDoesNotExist) + throw new SignalDoesNotExist(e.getCause()); + else + e.printStackTrace(); + } + + return outputSignal; + } +} diff --git a/asm/src/math/ConvCorr.java b/asm/src/math/ConvCorr.java new file mode 100644 index 0000000..e74c152 --- /dev/null +++ b/asm/src/math/ConvCorr.java @@ -0,0 +1,249 @@ +package math; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import exceptions.SignalDoesNotExist; +import signals.Signal; +import signals.Windowing; +import util.Util; + +public class ConvCorr extends MathBase { + + public static final Map convcorr = new HashMap() { + { + put("convolution", new String[] {"ConvolutionCi",""}); + put("correlation", new String[] {"CorrelationCi",""}); + } + }; + + public ConvCorr(Map signals, CommandLineParser cp) { + super(signals, cp); + } + + private void convolutionCorrelation(Signal signal1, Signal signal2, int windowing, Signal outputSignal, boolean convolution) { + + //if ((DataDomain(vp[in_im1]) != REAL) || (DataDomain(vp[in_im2]) != REAL)) + // return ERR_DOMAIN; /*verkeerde domein */ + + if ( (signal1.getDataLength() != signal2.getDataLength()) || (signal1.getDataRecords() != signal2.getDataRecords()) || + (signal1.getDataChannels() != signal2.getDataChannels()) ) { + // TODO size error. + cp.println("size error"); + return; + } + + if(signal1.getDataLength() > (Math.pow(2,(Signal.MAX_N-1)))) { + // TODO too long error + cp.println("too long error"); + return ; + } + + double [] real_in1 = signal1.getRealData(); + double [] imag_in1 = signal1.getImagData(); + double [] real_in2 = signal2.getRealData(); + double [] imag_in2 = signal2.getImagData(); + int alloc_size = 2*real_in1.length; + double [] real_data_out = new double[alloc_size]; + double [] imag_data_out = new double[alloc_size]; + + outputSignal.setDataType(Signal.COMP); + outputSignal.setRecord(0); + outputSignal.setChannel(0); + outputSignal.setRealData(real_data_out); + outputSignal.setImagData(imag_data_out); + outputSignal.setDataLength(2*signal1.getDataLength()); + + int inputDataLength = signal1.getDataLength(); + outputSignal.setDataLength(2*signal1.getDataLength()); /* Vanwege zeropad */ + + int window_lengte = inputDataLength; + int fft_lengte = outputSignal.getDataLength(); + cp.println(String.format("fft_length %d", fft_lengte)); + + /* Vraag geheugen aan voor de hulp pointers */ + double [] real_hulp1 = new double[alloc_size]; + double [] imag_hulp1 = new double[alloc_size]; + double [] real_hulp2 = new double[alloc_size]; + double [] imag_hulp2 = new double[alloc_size]; + + /* Copieer en Zeropad de ingangs signalen */ + for (int channel = 0;channel < signal1.getDataChannels(); channel++) + { + for (int record = 0;record < signal1.getDataRecords(); record++) + { + /* offset betreffende record */ + int offset_in = (channel*signal1.getDataRecords() + record)*inputDataLength; + int offset_out = 2*offset_in; + for (int i=0;i < inputDataLength;i++) + { + real_hulp1[i+offset_out] = real_in1[i+offset_in]; + imag_hulp1[i+offset_out] = imag_in1[i+offset_in]; + real_hulp2[i+offset_out] = real_in2[i+offset_in]; + imag_hulp2[i+offset_out] = imag_in2[i+offset_in]; + } + // default double value is 0.0. + } + } + + for (int channel=0; channel < signal1.getDataChannels(); channel++) + { + for (int record=0; record < signal1.getDataRecords(); record++) + { + /* Vermenigvuldig de ingangsdata met een window en doe de fft */ + int offset = (channel*signal1.getDataRecords() + record)*inputDataLength; + Windowing.windowing(real_hulp1,imag_hulp1,real_hulp1,imag_hulp1,offset,window_lengte,windowing); + Windowing.windowing(real_hulp2,imag_hulp2,real_hulp2,imag_hulp2,offset,window_lengte,windowing); + + Transformations.fft(real_hulp1,imag_hulp1,offset,fft_lengte,1); + Transformations.fft(real_hulp2,imag_hulp2,offset,fft_lengte,1); + } + } + + if (convolution) { + /* Multiply hulp1 with hulp2 */ + for (int i=0;i < real_hulp1.length;i++) { + double temp = real_hulp1[i]; + real_hulp1[i] = (real_hulp1[i]*real_hulp2[i] - imag_hulp1[i]*imag_hulp2[i]); + imag_hulp1[i] = (temp*imag_hulp2[i] + imag_hulp1[i]*real_hulp2[i]); + } + } else { + // Correlation. Multiply complex conjugate of hulp1 with hulp2; + for (int i=0;i < real_hulp1.length;i++) { + double temp = real_hulp1[i]; + real_hulp1[i] = (real_hulp1[i]*real_hulp2[i] - (-imag_hulp1[i])*imag_hulp2[i]); + imag_hulp1[i] = (temp*imag_hulp2[i] + (-imag_hulp1[i])*real_hulp2[i]); + } + } + + /* Doe de inverse FFT van het resultaat */ + for (int channel=0; channel < signal1.getDataChannels(); channel++) + { + for (int record=0; record < signal1.getDataRecords(); record++) + { + /* Doe de ifft */ + int offset = (channel*signal1.getDataRecords() + record)*inputDataLength; + Transformations.fft(real_hulp1,imag_hulp1,offset,fft_lengte,-1); + } + } + + /* Zet de data in out_im */ + for (int i=0;i < real_data_out.length;i++) + { + real_data_out[i] = real_hulp1[i]; + imag_data_out[i] = imag_hulp1[i]; + } + } + + public Signal CorrelationCi(List arguments, String command) throws SignalDoesNotExist { + String signalname1 = cp.getString(arguments, "Signal", "a"); + String signalname2 = cp.getString(arguments, "Signal", "b"); + + Signal signal1 = signals.get(signalname1); /* Find the correct signal */ + if (signal1 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname1 + "\" does not exist."); + } + if (signal1.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + Signal signal2 = signals.get(signalname2); /* Find the correct signal */ + if (signal2 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname2 + "\" does not exist."); + } + if (signal2.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal1); + + int windowing = cp.getInt(arguments, "Window type", 0, 6, 0); + convolutionCorrelation(signal1, signal2, windowing, outputSignal, false); + return outputSignal; + } + + public Signal ConvolutionCi(List arguments, String command) throws SignalDoesNotExist { + String signalname1 = cp.getString(arguments, "Signal", "a"); + String signalname2 = cp.getString(arguments, "Signal", "b"); + + Signal signal1 = signals.get(signalname1); /* Find the correct signal */ + if (signal1 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname1 + "\" does not exist."); + } + if (signal1.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + Signal signal2 = signals.get(signalname2); /* Find the correct signal */ + if (signal2 == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname2 + "\" does not exist."); + } + if (signal2.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal1); + + int windowing = cp.getInt(arguments, "Window type", 0, 6, 0); + convolutionCorrelation(signal1, signal2, windowing, outputSignal, true); + return outputSignal; + } + + public Signal ConvCorrCi(List arguments, String command) throws SignalDoesNotExist { + Signal outputSignal = null; + + Method method = null; + String methodName = convcorr.get(command)[0]; + try { + method = this.getClass().getMethod(methodName, List.class, String.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + outputSignal = (Signal) method.invoke(this, arguments, command); + } catch (IllegalAccessException | IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof SignalDoesNotExist) + throw new SignalDoesNotExist(e.getCause()); + else + e.printStackTrace(); + } + + return outputSignal; + } +} diff --git a/asm/src/math/FFT.java b/asm/src/math/FFT.java new file mode 100644 index 0000000..efad42e --- /dev/null +++ b/asm/src/math/FFT.java @@ -0,0 +1,78 @@ +package math; + +public class FFT { + + public FFT() { + // TODO Auto-generated constructor stub + } + + /** + * Perform a one dimensional FFT in place. + * + * @param real + * @param imag + * @param npoints length of array. + * @param dir 1: forward fft, -1: inverse fft. + * @return + */ + public static int fft(double[] real, double[] imag, int npoints, int dir) { + double temp; + double tr, ti, angle, wr, wi; + + /* Swap the input elements for the decimation in time algorithm. */ + + for (int index = 1, swapindex = 0; index < npoints; index++) { + int k = npoints; + do + k /= 2; + while ((swapindex + k) >= npoints); + swapindex = (swapindex % k) + k; + if (swapindex <= index) + continue; + temp = real[index]; + real[index] = real[swapindex]; + real[swapindex] = temp; + temp = imag[index]; + imag[index] = imag[swapindex]; + imag[swapindex] = temp; + } + + /* + * Do the butterfly computations. + * + * stage index: k = 1, 2, 4, 8 . . . For npoints = 8, for example, there will be + * three stages of butterfly computations. b'fly indices: i and j will be + * separated by a distance dependent on the current stage. k is used as the + * separation constant. + */ + + for (int k = 1; k < npoints; k *= 2) { + for (int index = 0; index < k; index++) { + angle = Math.PI * ((double) (index * -dir)) / ((double) k); + wr = Math.cos(angle); + wi = Math.sin(angle); + for (int i = index; i < npoints; i += 2 * k) { + int j = i + k; + tr = (wr * real[j]) - (wi * imag[j]); + ti = (wr * imag[j]) + (wi * real[j]); + + real[j] = real[i] - tr; + imag[j] = imag[i] - ti; + real[i] += tr; + imag[i] += ti; + } + } + } + + wr = Math.sqrt(1.0 / (double) npoints); + + /* scale the output by sqrt(1./N) */ + + for (int i = 0; i < npoints; i++) { + real[i] *= wr; + imag[i] *= wr; + } + return 0; + } + +} diff --git a/asm/src/math/MathBase.java b/asm/src/math/MathBase.java new file mode 100644 index 0000000..0e0b9f6 --- /dev/null +++ b/asm/src/math/MathBase.java @@ -0,0 +1,36 @@ +package math; + +import java.util.Map; + +import console.CommandLineParser; +import signals.Signal; + +public class MathBase { + protected final Map signals; + protected CommandLineParser cp; + + public MathBase(Map signals, CommandLineParser cp) { + this.signals = signals; + this.cp = cp; + } + + protected void setSignalValues(Signal outPutSignal, Signal inputSignal) { + outPutSignal.setDate(); + outPutSignal.setPixelFormat(Signal.DATA_PIXEL_FORMAT); + outPutSignal.setDataLength(inputSignal.getDataLength()); + outPutSignal.setDataRecords(inputSignal.getDataRecords()); + outPutSignal.setDataFileSeq(Signal.DATA_FILE_SEQ); + outPutSignal.setDataBitsPerSample(Signal.BPS_SAMPLE); + outPutSignal.setDataChannels(inputSignal.getDataChannels()); + outPutSignal.setDataSampleRate(inputSignal.getDataSampleRate()); + outPutSignal.setDataDomain(Signal.TIME); + outPutSignal.setDataType(inputSignal.getDataType()); + outPutSignal.setDataIdString(Signal.ASM_ID_STRING); + outPutSignal.setDataUserText("DataUserText"); + outPutSignal.setDataDescription(inputSignal.getDataDescription()); + outPutSignal.setMode(inputSignal.getMode()); + outPutSignal.setRecord(inputSignal.getRecord()); + outPutSignal.setChannel(inputSignal.getChannel()); + outPutSignal.setHScale(inputSignal.getHScale()); + } +} diff --git a/asm/src/math/Transformations.java b/asm/src/math/Transformations.java new file mode 100644 index 0000000..6f8eed2 --- /dev/null +++ b/asm/src/math/Transformations.java @@ -0,0 +1,509 @@ +package math; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import exceptions.SignalDoesNotExist; +import signals.Signal; +import signals.Windowing; + +public class Transformations extends MathBase { + + public static final Map transformations = new HashMap() { + { + put("fft", new String[]{"FFTCi",""}); + put("ifft", new String[]{"IFFTCi",""}); + put("magnitude", new String[]{"MagnitudeCi",""}); + put("phase", new String[]{"PhaseCi",""}); + put("histogram", new String[]{"HistCi",""}); + } + }; + + public Transformations(Map signals, CommandLineParser cp) { + super(signals, cp); + } + + public static void fft(double[] real, double[] imag, int offset, int fft_length, int dir) { + double re[] = Arrays.copyOfRange(real, offset, offset + fft_length); + double im[] = Arrays.copyOfRange(imag, offset, offset + fft_length); + FFT.fft(re, im, fft_length, dir); + for (int i = 0; i < fft_length; i++) { + real[offset + i] = re[i]; + imag[offset + i] = im[i]; + } + } + + public void fft(Signal signal, int length, int windowing, int mid_type, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int fft_length = (int) Math.pow(2.0, length); + if (fft_length > signal.getDataLength()) + fft_length = signal.getDataLength(); + int records_out = ((signal.getDataLength() * signal.getDataRecords()) / fft_length); + cp.println("fft_length = " + fft_length); + cp.println("records_out = " + records_out); + double[] re_out = new double[dataLength]; + double[] im_out = new double[dataLength]; + + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + + for (int record = 0; record < records_out; record++) { + int offset = (channel * records_out + record) * fft_length; + Windowing.windowing(re, im, re_out, im_out, offset, fft_length, windowing); + fft(re_out, im_out, offset, fft_length, 1); + } + } + outputSignal.setDataRecords(records_out); + outputSignal.setDataLength(fft_length); + outputSignal.setDataDomain(Signal.FREQ); + outputSignal.setDataType(Signal.COMP); + outputSignal.setMode(Signal.BODE_M); + outputSignal.setAverageType(mid_type); + outputSignal.setRecord(0); + outputSignal.setChannel(0); + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal FFTCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + int l_max = (int) (Math.log10(signal.getDataLength()) / Math.log10(2.0)); + int length = cp.getInt(arguments, "Size (2^n)", Signal.MIN_N, l_max, l_max); + int windowing = cp.getInt(arguments, "Window type", 0, 6, 1); + int mid_type = cp.getInt(arguments, "Average type", 0, 1, 0); + fft(signal, length, windowing, mid_type, outputSignal); + return outputSignal; + } + + public void ifft(Signal signal, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int totalLength = signal.getDataChannels() * signal.getDataRecords() * dataLength; + double[] re_out = new double[totalLength]; + double[] im_out = new double[totalLength]; + + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + + for (int record = 0; record < signal.getDataRecords(); record++) { + int offset = (channel * signal.getDataRecords() + record) * dataLength; + fft(re_out, im_out, offset, dataLength, -1); + } + } + outputSignal.setDataDomain(Signal.TIME); + outputSignal.setDataType(Signal.COMP); + outputSignal.setMode(Signal.REAL_M); + outputSignal.setRecord(0); + outputSignal.setChannel(0); + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal IFFTCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.FREQ) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + ifft(signal, outputSignal); + return outputSignal; + } + + public void magnitude(Signal signal, int channel_nr, int mid_type, int log, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int channelLength = signal.getDataRecords() * signal.getDataLength(); + // The output signals will have channels reduced to 1 record. + double[] re_out = new double[signal.getDataChannels() * signal.getDataLength()]; + double[] im_out = new double[signal.getDataChannels() * signal.getDataLength()]; + + double[] cum1 = new double[signal.getDataLength()]; + + if (mid_type == 0) { + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + int offset = channel * channelLength; + for (int record = 0; record < signal.getDataRecords(); record++) { + for (int i = 0; i < dataLength; i++) { + int data_nr = offset + record * dataLength + i; + double temp = Math.sqrt(Math.pow(re[data_nr], 2) + Math.pow(im[data_nr], 2)); + /* Tel de magnitudes bij elkaar op */ + cum1[i] = cum1[i] + temp; + } + } + for (int i = 0; i < dataLength; i++) { + /* Deel de cumulatieve magnitudes door het aantal records */ + cum1[i] = cum1[i] / (double) signal.getDataRecords(); + /* In het magnitude domein bevatten de channels altijd maar 1 record */ + re_out[i + channel * dataLength] = cum1[i]; + im_out[i + channel * dataLength] = 0.0; + cum1[i] = 0.0; /* leeg maken voor volgende channel */ + } + } + } + if (mid_type == 1) { + double[] cum2 = new double[signal.getDataLength()]; + for (int h = 0; h < signal.getDataChannels(); h++) { + /* offset van betreffende channel */ + int offs = h * signal.getDataRecords() * dataLength; + + for (int j = 0; j < signal.getDataRecords(); j++) { + /* Tel de records bij van een channel elkaar op */ + for (int i = 0; i < dataLength; i++) { + cum1[i] = cum1[i] + (re[offs + i + j * dataLength]); + cum2[i] = cum2[i] + (im[offs + i + j * dataLength]); + } + } + for (int i = 0; i < dataLength; i++) { + /* Deel door het aantal records */ + cum1[i] = cum1[i] / (double) (signal.getDataRecords()); + cum2[i] = cum2[i] / (double) (signal.getDataRecords()); + + /* Bepaal de magnitude */ + /* In het magnitude domein bevatten de channels altijd maar 1 record */ + re_out[i + h * dataLength] = Math.sqrt(Math.pow(cum1[i], 2) + Math.pow(cum2[i], 2)); + im_out[i + h * dataLength] = 0.0; + + cum1[i] = cum2[i] = 0.0; /* leeg maken voor volgend channel */ + } + } + } + outputSignal.setDataRecords(1); + outputSignal.setDataDomain(Signal.MAGN); + outputSignal.setMode(Signal.MAGN_M); + outputSignal.setDataType(Signal.REAL); + outputSignal.setRecord(0); + outputSignal.setChannel(channel_nr); + outputSignal.setLog(log); + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal MagnitudeCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.FREQ) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + int channel_nr = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int mid_type = cp.getInt(arguments, "Average type", 0, 1, 0); + int log = cp.getInt(arguments, "Log magnitude", 0, 1, 0); + magnitude(signal, channel_nr, mid_type, log, outputSignal); + return outputSignal; + } + + public void phase(Signal signal, int channel_nr, int mid_type, Signal outputSignal) { + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int dataLength = signal.getDataLength(); + int channelLength = signal.getDataRecords() * signal.getDataLength(); + // The output signals will have channels reduced to 1 record. + double[] re_out = new double[signal.getDataChannels() * signal.getDataLength()]; + double[] im_out = new double[signal.getDataChannels() * signal.getDataLength()]; + + double[] cum1 = new double[dataLength]; + + if (mid_type == 0) { + for (int h = 0; h < signal.getDataChannels(); h++) /* aantal channels */ + { + + for (int j = 0; j < signal.getDataRecords(); j++) /* aantal records */ + { + /* Bereken het adres van record j in channel h */ + int offset = h * channelLength + j * dataLength; + for (int i = 0; i < dataLength; i++) /* record-lengte */ + { + /* bepaal de phase */ + double temp = (180 / Math.PI) * Math.atan2((im[i + offset]), (re[i + offset])); + cum1[i] = cum1[i] + temp; /* Cumulatief */ + } + } + + /* Bereken het adres van channel h */ + /* In het fase domein bevat een channel altijd maar 1 record */ + int offset = h * dataLength; + + /* Deel de cumulatieve fase door het aantal records */ + for (int i = 0; i < dataLength; i++) { + re_out[i + offset] = cum1[i] / (double) (signal.getDataRecords()); + im_out[i + offset] = 0.0; + cum1[i] = 0.0; /* leeg maken voor volgende channel */ + } + } + } + if (mid_type == 1) { + double[] cum2 = new double[dataLength]; + for (int h = 0; h < signal.getDataChannels(); h++) { + + for (int j = 0; j < signal.getDataRecords(); j++) { + /* Bereken het adres van record j in channel h */ + int offset = h * channelLength + j * dataLength; + for (int i = 0; i < dataLength; i++) { + /* Tel de records bij elkaar op */ + cum1[i] = cum1[i] + re[i + offset]; + cum2[i] = cum2[i] + im[i + offset]; + } + } + + /* Bereken het adres van channel h */ + /* In het fase domein bevat een channel altijd maar 1 record */ + int offset = h * dataLength; + + for (int i = 0; i < dataLength; i++) { + /* deel door het aantal records */ + cum1[i] = cum1[i] / (double) (signal.getDataRecords()); + cum2[i] = cum2[i] / (double) (signal.getDataRecords()); + /* Bepaal de fase */ + re_out[i + offset] = (180 / Math.PI) * Math.atan2(cum2[i], cum1[i]); + im_out[i + offset] = 0.0; + + cum1[i] = cum2[i] = 0.0; /* leeg maken voor volgend channel */ + } + } + } + outputSignal.setDataRecords(1); + outputSignal.setDataDomain(Signal.PHAS); + outputSignal.setMode(Signal.PHAS_M); + outputSignal.setDataType(Signal.REAL); + outputSignal.setRecord(0); + outputSignal.setChannel(channel_nr); + outputSignal.setRealData(re_out); + outputSignal.setImagData(im_out); + } + + public Signal PhaseCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.FREQ) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + int channel_nr = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int mid_type = cp.getInt(arguments, "Average type", 0, 1, 0); + phase(signal, channel_nr, mid_type, outputSignal); + return outputSignal; + } + + public void histogram(Signal signal, int buckets, Signal outputSignal) { + + int lengte; + int offset_in, offset_out; + int bucket; + double Delta; + // char buffer1[128],buffer2[128]; + boolean bucket_found; + int dataLength = signal.getDataLength(); + buckets = (int) Math.pow(2, buckets); + int alloc_size = signal.getDataChannels() * buckets; + lengte = signal.getDataRecords() * dataLength; /* channel lengte */ + + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + double[] re_out = new double[alloc_size]; + double[] im_out = new double[alloc_size]; + + double[] real_hulp = Arrays.copyOfRange(re, 0, re.length); + + outputSignal.setRealData(re_out); /* Zet de pointers van de data weer terug */ + outputSignal.setImagData(im_out); + + outputSignal.setDataLength(buckets); + outputSignal.setDataRecords(1); + outputSignal.setDataType(Signal.REAL); + outputSignal.setDataDomain(Signal.AMPL); + outputSignal.setMode(Signal.HIST_M); + outputSignal.setRecord(0); + outputSignal.setHScale(signal.getHScale()); + + for (int channel = 0; channel < signal.getDataChannels(); channel++) { + /* Het histogram wordt per channel van het ingangssignaal bepaalt */ + /* In het histogram gaat het om de magnitude */ + + /* Bereken de offset van het channel */ + offset_in = channel * lengte; + offset_out = (channel) * outputSignal.getDataRecords() * outputSignal.getDataLength(); + + double reMin, reMax; + reMin = reMax = Math.sqrt(Math.pow(real_hulp[offset_in], 2) + Math.pow(im[offset_in], 2)); + + /* Bepaal van de elementen de magnitude en het maximum en minimum */ + for (int element = 0; element < lengte; element++) { + real_hulp[element + offset_in] = Math.sqrt( + Math.pow(real_hulp[element + offset_in], 2) + Math.pow(im[element + offset_in], 2)); + if (real_hulp[element + offset_in] > reMax) + reMax = real_hulp[element + offset_in]; + if (real_hulp[element + offset_in] < reMin) + reMin = real_hulp[element + offset_in]; + } + // FIXME: max and min are overwritten by every next channel. + outputSignal.setRealMaximum(reMax); + outputSignal.setRealMinimum(reMin); + + Delta = (double) ((reMax - reMin) / (double) (buckets)); + + /* Maak de elementen van out_im 0 */ + for (int i = 0; i < (outputSignal.getDataRecords() * outputSignal.getDataLength()); i++) { + re_out[i + offset_out] = 0.0; + im_out[i + offset_out] = 0.0; + } + + for (int i = 0; i < lengte; i++) { + bucket = buckets / 2; + bucket_found = false; + + for (int j = (buckets / 2); (j > 0) && (bucket_found == false); j = (int) (j / 2)) { + if (real_hulp[i + offset_in] >= (reMin + ((double) bucket + 1.0) * Delta)) + bucket = bucket + (int) (j / 2); + else { + if (real_hulp[i + offset_in] < (reMin + (double) bucket * Delta)) + bucket = bucket - (int) (j / 2); + else + bucket_found = true; + } + if (real_hulp[i + offset_in] < (reMin + Delta)) { + bucket = 0; + bucket_found = true; + } + } + re_out[offset_out + bucket] = re_out[offset_out + bucket] + 1; + } + } + } + + public Signal HistCi(List arguments, String command) throws SignalDoesNotExist { + String signalname = cp.getString(arguments, "Signal", "a"); + + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + if (signal.getDataDomain() != Signal.TIME) { + // TODO domain error + cp.println("domain error"); + return null; + } + String outputSignalName = cp.getString(arguments, "Signal", command); + + Signal outputSignal = signals.get(outputSignalName); + if (outputSignal == null) /* Signal did not exist yet */ + { + outputSignal = new Signal(outputSignalName); + signals.put(outputSignalName, outputSignal); + } + setSignalValues(outputSignal, signal); + + int buckets = cp.getInt(arguments, "Buckets (2^n)", Signal.MIN_N, + (int) (Math.log(signal.getDataLength()) / Math.log(2)), + (int) (Math.log(signal.getDataLength()) / Math.log(2))); + histogram(signal, buckets, outputSignal); + return outputSignal; + } + + public Signal TransformationCi(List arguments, String command) throws SignalDoesNotExist { + Signal outputSignal = null; + + Method method = null; + String methodName = transformations.get(command)[0]; + try { + method = this.getClass().getMethod(methodName, List.class, String.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + outputSignal = (Signal) method.invoke(this, arguments, command); + } catch (IllegalAccessException | IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof SignalDoesNotExist) + throw new SignalDoesNotExist(e.getCause()); + else + e.printStackTrace(); + } + + return outputSignal; + } +} \ No newline at end of file diff --git a/asm/src/signals/PlotCommands.java b/asm/src/signals/PlotCommands.java new file mode 100644 index 0000000..aa9a422 --- /dev/null +++ b/asm/src/signals/PlotCommands.java @@ -0,0 +1,235 @@ +package signals; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; +import exceptions.SignalDoesNotExist; + +public class PlotCommands { + protected final Map signals; + protected CommandLineParser cp; + + public static final Map plotcommands = new HashMap() { + { + put("bode", new String[]{"BodeCi",""}); + put("display", new String[]{"DisplayCi",""}); + put("imaginary", new String[]{"ImagCi",""}); + put("info", new String[]{"InfoCi",""}); + put("list", new String[]{"ListCi",""}); + put("print", new String[]{"PrintCi",""}); + put("real", new String[]{"RealCi",""}); + put("rename", new String[]{"RenameCi",""}); + put("readf", new String[]{"ReadCi",""}); + put("writef", new String[]{"WriteCi",""}); + put("xscale", new String[]{"XscaleCi",""}); + } + }; + + public PlotCommands(Map signals, CommandLineParser cp) { + this.signals = signals; + this.cp = cp; + } + + public Signal DisplayCi(List arguments, Signal signal) { + int channel = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int record = cp.getInt(arguments, "Record", 0, signal.getDataRecords() - 1, 0); + signal.setChannel(channel); + signal.setRecord(record); + return signal; + } + + public Signal RealCi(List arguments, Signal signal) { + if (signal.getDataType() == Signal.IMAG) { + cp.println("No real part present."); + return null; + } + if (!(signal.getDataDomain() == Signal.TIME || signal.getDataDomain() == Signal.FREQ)) { + // TODO domain error + cp.println("domain error"); + return null; + } + + int channel = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int record = cp.getInt(arguments, "Record", 0, signal.getDataRecords() - 1, 0); + signal.setChannel(channel); + signal.setRecord(record); + signal.setMode(Signal.REAL_M); + return signal; + } + + public Signal ImagCi(List arguments, Signal signal) { + if (signal.getDataType() == Signal.REAL) { + cp.println("No imaginary part present."); + return null; + } + if (!(signal.getDataDomain() == Signal.TIME || signal.getDataDomain() == Signal.FREQ)) { + // TODO domain error + cp.println("domain error"); + return null; + } + + int channel = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int record = cp.getInt(arguments, "Record", 0, signal.getDataRecords() - 1, 0); + signal.setChannel(channel); + signal.setRecord(record); + signal.setMode(Signal.IMAG_M); + return signal; + } + + public Signal BodeCi(List arguments, Signal signal) { + if (signal.getDataDomain() != Signal.FREQ) { + // TODO domain error + cp.println("domain error"); + return null; + } + + int channel = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int averageType = cp.getInt(arguments, "Average type", 0, 1, 0); + signal.setChannel(channel); + signal.setAverageType(averageType); + signal.setMode(Signal.BODE_M); + return signal; + } + + public Signal XscaleCi(List arguments, Signal signal) { + double hscale = cp.getDouble(arguments, "Scalefactor", 0, 10, 1); + if (hscale == 0.0) { + cp.println("Illegal scale value 0.0"); + return null; + } + signal.setHScale(hscale); + return signal; + } + + public Signal InfoCi(List arguments, Signal signal) { + cp.println(String.format("PixelFormat : %d", signal.getPixelFormat())); + cp.println(String.format("RecordLength : %d", signal.getDataLength())); + cp.println(String.format("Number of Records : %d", signal.getDataRecords())); + cp.println(String.format("Number of Channels : %d", signal.getDataChannels())); + cp.println(String.format("Fileseq. Nr. : %d", signal.getDataFileSeq())); + cp.println(String.format("Bits per sample : %d", signal.getDataBitsPerSample())); + cp.println(String.format("Samplerate : %d", signal.getDataSampleRate())); + cp.println(String.format("Domain : %d", signal.getDataDomain())); + cp.println(String.format("Type : %s", signal.getDataTypeToString())); + cp.println(String.format("ASM-Id String : %s", signal.getDataIdString())); + cp.println(String.format("Signal-Name : %s", signal.getName())); + cp.println(String.format("UserText : %s", signal.getDataUserText())); + cp.println(String.format("Date : %s", signal.getDate())); + cp.println(String.format("Description : %s", signal.getDataDescription())); + cp.println(String.format("X Scale : %f", signal.getHScale())); + + return null; + } + + public Signal PrintCi(List arguments, Signal signal) { + int channel = cp.getInt(arguments, "Channel", 0, signal.getDataChannels() - 1, 0); + int record = cp.getInt(arguments, "Record", 0, signal.getDataRecords() - 1, 0); + + double[] re = signal.getRealData(); + double[] im = signal.getImagData(); + int offset = (channel * signal.getDataRecords() + record) * signal.getDataLength(); + for (int i = 0; i < signal.getDataLength(); i++) { + cp.println(String.format("%6d) Re: %g Im: %g", i, re[i + offset], im[i + offset])); + } + return null; + } + + public Signal RenameCi(List arguments, Signal signal) { + String newName = cp.getString(arguments, "new name", signal.getName()); + if (signals.get(newName) != null) { + cp.println("Signal " + newName + " already exists."); + return null; + } + + signals.remove(signal.getName()); + signal.setName(newName); + signals.put(newName,signal); + return signal; + } + + public Signal ReadCi(List arguments) throws IOException { + String fileName = cp.getString(arguments, "file name", ""); + String signalName = cp.getString(arguments, "signal name", ""); + Path path = Paths.get(fileName); + Signal signal = new Signal("readf"); + signal.read(path); + if (!signalName.isEmpty()) { + signal.setName(signalName); + } + if (signal.getDataDomain() == Signal.FREQ) { + signal.setMode(Signal.BODE_M); + } + + Signal signalSameName = signals.get(signal.getName()); + if (signalSameName != null) { + cp.closeSignal(signalSameName); + } + + signals.put(signal.getName(), signal); + cp.println("Read file " + path.toAbsolutePath()); + return signal; + } + + public Signal WriteCi(List arguments, Signal signal) throws IOException { + String fileName = cp.getString(arguments, "file name", signal.getName() + ".asm"); + String userText = cp.getString(arguments, "user text", ""); + String description = cp.getString(arguments, "description", ""); + Path path = Paths.get(fileName); + if (!userText.isEmpty()) + signal.setDataUserText(userText); + if (!description.isEmpty()) + signal.setDataDescription(description); + signal.write(path); + cp.println("Wrote file " + path.toAbsolutePath()); + return signal; + } + + public Signal PlotCommandsCi(List arguments, String command) throws SignalDoesNotExist, IOException { + + if (command.equals("readf")) { + return ReadCi(arguments); + } + + String signalname = cp.getString(arguments, "Signal", ""); + Signal signal = signals.get(signalname); /* Find the correct signal */ + if (signal == null) /* Signal does not exist */ + { + throw new SignalDoesNotExist("Signal \"" + signalname + "\" does not exist."); + } + + Signal outputSignal = null; + + Method method = null; + String methodName = plotcommands.get(command)[0]; + try { + method = this.getClass().getMethod(methodName, List.class, Signal.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + outputSignal = (Signal) method.invoke(this, arguments, signal); + } catch (IllegalAccessException | IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof SignalDoesNotExist) + throw new SignalDoesNotExist(e.getCause()); + else + e.printStackTrace(); + } + + return outputSignal; + } +} \ No newline at end of file diff --git a/asm/src/signals/Signal.java b/asm/src/signals/Signal.java new file mode 100644 index 0000000..8df4f21 --- /dev/null +++ b/asm/src/signals/Signal.java @@ -0,0 +1,509 @@ +package signals; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +public class Signal { + private SignalWindow window = null; + public static final short DATA_PIXEL_FORMAT = 0; + public static final short DATA_FILE_SEQ = 0; + + // Data domain + public static final short TIME = 0; + public static final short FREQ = 1; + public static final short AMPL = 2; + public static final short MAGN = 3; + public static final short PHAS = 4; + + public static final short REAL = 0; + public static final short IMAG = 1; + public static final short COMP = 2; + + /* Mode of the signal to plot */ + public static final int REAL_M = 0; + public static final int IMAG_M = 1; + public static final int HIST_M = 2; + public static final int MAGN_M = 3; + public static final int PHAS_M = 4; + public static final int BODE_M = 5; + + public static final short BPS_CHAR = 8; + public static final short BPS_SHORT = 16; + public static final short BPS_INT = 32; + public static final short BPS_FLOAT = 3232; + public static final short BPS_DOUBLE = 6464; + public static final short BPS_SAMPLE = 6464; + + public static final int SAMPLE_RATE = 1024; + public static final int MIN_N = 7; /* Minimal length of a record = 256 */ + public static final int MAX_N = 12; /* Maximal length of a record = 4096 */ + + public static final String ASM_ID_STRING = "ASM 2.0"; + + AsmHeader header; + int Wlenx; /* x - dimension */ + int Wleny; /* y - dimension */ + int display_mode; /* don, <1-5> */ + double vscale = 1.0; /* vertikale scale factor */ + double hscale = 1.0; /* horizontale scale factor */ + int averageType = 0; + double maximum; /* maximale waarde van een array */ + double minimum; /* minimale waarde van een array */ + byte[] windowName; /* window name */ + byte[] fileName; + int log = 0; /* log axis ? */ + int record_nr = 0; /* number of displayed record */ + int channel_nr = 0; /* number of displayed channel */ + int Mode; /* window containes real,imag,bode,phase,magn */ + Boolean filled = false; /* window is used */ + int image; /* window handle */ + Diagram diagram; /* diagram structure */ + + public Signal(String name) { + this.windowName = new byte[40]; + this.fileName = new byte[256]; + this.header = new AsmHeader(); + this.diagram = new Diagram(); + setName(name); + } + + public class AsmHeader { + short pixel_format; /* 0 = unpacked 1 = packed */ + int length; /* Aantal samples per record */ + int n_channels; /* Aantal channels */ + short file_seq; /* File sequence number = 0 */ + short bits_p_samp; /* bps 8, 16, 32, 3232, 6464 */ + int n_records; /* Aantal records */ + short domain_id; /* 0=time, 1=freq, 2=ampl, 3=magnitude, 4= fase */ + short datatype_id; /* 0=real, 1=imaginair, 2= complex */ + double[] real_data; /* pointer to real data */ + double[] imag_data; /* pointer to imaginary data */ + int sample_rate; /* Sample-rate in 10 Hz */ + short[] reserved; /* Gereserveerd */ + double[] numerical; + byte[] asm_id_string; + byte[] signal_name; + byte[] user_text; + byte[] date; + byte[] description; + + public AsmHeader() { + reserved = new short[19]; + numerical = new double[24]; + asm_id_string = new byte[74]; + signal_name = new byte[32]; + user_text = new byte[46]; + date = new byte[30]; + description = new byte[74]; + } + } + + public class Diagram { + byte[] data; + int length; + int size; + } + + /** + * Convert a byte array with a fixed length to a string. The array may be longer + * than the actual string length. The string stops at the first 0 byte, like a C + * char array. + * + * @param source + * @return + */ + + private String arrayToString(byte[] source) { + int len = 0; + for (int i = 0; i < source.length; i++) { + if (source[i] == '\0') { + len = i; + break; + } + } + return new String(source, 0, len); + } + + private void copyByteArray(byte[] target, String source) { + int i; + byte[] sourceByte = source.getBytes(); + for (i = 0; (i < sourceByte.length) && (i < target.length - 1); i++) { + target[i] = sourceByte[i]; + } + target[i] = '\0'; + } + + public String getName() { + return arrayToString(header.signal_name); + } + + public short getPixelFormat() { + return header.pixel_format; + } + + /** + * + * + * @return The number of samples per record. + */ + public int getDataLength() { + return header.length; + } + + public String getDate() { + return arrayToString(header.date); + } + + public String getDataIdString() { + return arrayToString(header.asm_id_string); + } + + public String getDataUserText() { + return arrayToString(header.user_text); + } + + public String getDataDescription() { + return arrayToString(header.description); + } + + public double getHScale() { + return this.hscale; + } + + public double getVScale() { + return this.vscale; + } + + public int getAverageType() { + return this.averageType; + } + + public int getMode() { + return this.Mode; + } + + public int getWindowWidth() { + return this.Wlenx; + } + + public int getWindowHeight() { + return this.Wleny; + } + + public short getDataType() { + return header.datatype_id; + } + + public String getDataTypeToString() { + String type; + switch (header.datatype_id) { + case Signal.REAL: + type = "real"; + break; + case Signal.IMAG: + type = "imaginary"; + break; + case Signal.COMP: + type = "complex"; + break; + default: + type = "unknown"; + break; + } + return type; + } + + public short getDataDomain() { + return header.domain_id; + } + + public short getDataFileSeq() { + return header.file_seq; + } + + public short getDataBitsPerSample() { + return header.bits_p_samp; + } + + public int getDataChannels() { + return header.n_channels; + } + + public int getDataSampleRate() { + return header.sample_rate; + } + + public double[] getRealData() { + return header.real_data; + } + + public double[] getImagData() { + return header.imag_data; + } + + public double getMinimum() { + return this.minimum; + } + + public double getMaximum() { + return this.maximum; + } + + public double getRealMaximum() { + return header.numerical[0]; + } + + public double getImagMaximum() { + return header.numerical[1]; + } + + public double getRealMinimum() { + return header.numerical[2]; + } + + public double getImagMinimum() { + return header.numerical[3]; + } + + public int getRecord() { + return this.record_nr; + } + + public int getChannel() { + return this.channel_nr; + } + + public int getDataRecords() { + return header.n_records; + } + + public int getLog() { + return this.log; + } + + public void setName(String name) { + copyByteArray(header.signal_name, name); + } + + public void setDate() { + Date date = Calendar.getInstance().getTime(); + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + String strDate = dateFormat.format(date); + copyByteArray(header.date, strDate); + } + + public void setPixelFormat(short format) { + header.pixel_format = format; + } + + public void setDataLength(int length) { + header.length = length; + } + + public void setDataRecords(int records) { + header.n_records = records; + } + + public void setDataFileSeq(short file_seq) { + header.file_seq = file_seq; + } + + public void setDataBitsPerSample(short bps) { + header.bits_p_samp = bps; + } + + public void setDataChannels(int channels) { + header.n_channels = channels; + } + + public void setDataSampleRate(int sampleRate) { + header.sample_rate = sampleRate; + } + + public void setDataDomain(short domain) { + header.domain_id = domain; + } + + public void setDataType(short type) { + header.datatype_id = type; + } + + public void setDataIdString(String id) { + copyByteArray(header.asm_id_string, id); + } + + public void setDataUserText(String userText) { + copyByteArray(header.user_text, userText); + } + + public void setDataDescription(String description) { + copyByteArray(header.description, description); + } + + public void setHScale(double scale) { + this.hscale = scale; + } + + public void setRecord(int record) { + this.record_nr = record; + } + + public void setLog(int log) { + this.log = log; + } + + public void setChannel(int channel) { + this.channel_nr = channel; + } + + public void setAverageType(int type) { + this.averageType = type; + } + + public void setMode(int mode) { + this.Mode = mode; + } + + public void setRealData(double[] data) { + header.real_data = data; + } + + public void setImagData(double[] data) { + header.imag_data = data; + } + + public void setWindowWidth(int width) { + this.Wlenx = width; + } + + public void setWindowHeight(int height) { + this.Wleny = height; + } + + public void setMinimum(double minimum) { + this.minimum = minimum; + } + + public void setMaximum(double maximum) { + this.maximum = maximum; + } + + public void setRealMaximum(double max) { + header.numerical[0] = max; + } + + public void setImagMaximum(double max) { + header.numerical[1] = max; + } + + public void setRealMinimum(double min) { + header.numerical[2] = min; + } + + public void setImagMinimum(double min) { + header.numerical[3] = min; + } + + public void setVScale(double scale) { + this.vscale = scale; + } + + public SignalWindow getWindow() { + return window; + } + + public void setWindow(SignalWindow window) { + this.window = window; + } + + public void write(Path outputFile) throws IOException { + + try (OutputStream os = Files.newOutputStream(outputFile); DataOutputStream out = new DataOutputStream(os)) { + out.writeShort(header.pixel_format); + out.writeInt(header.length); + out.writeInt(header.n_channels); + out.writeShort(header.file_seq); + out.writeShort(header.bits_p_samp); + out.writeInt(header.n_records); + out.writeShort(header.domain_id); + out.writeShort(header.datatype_id); + out.writeInt(header.sample_rate); + for (short r : header.reserved) + out.writeShort(r); + for (double n : header.numerical) + out.writeDouble(n); + out.write(header.asm_id_string); + out.write(header.signal_name); + out.write(header.user_text); + out.write(header.date); + out.write(header.description); + if (this.getDataType() == REAL || this.getDataType() == COMP) { + for (int i = 0; i < header.real_data.length; i++) { + out.writeDouble(header.real_data[i]); + } + } + if (this.getDataType() == IMAG || this.getDataType() == COMP) { + for (int i = 0; i < header.imag_data.length; i++) { + out.writeDouble(header.imag_data[i]); + } + } + out.flush(); + } + } + + public void read(Path outputFile) throws IOException { + + try (InputStream is = Files.newInputStream(outputFile); DataInputStream in = new DataInputStream(is)) { + this.setPixelFormat(in.readShort()); + this.setDataLength(in.readInt()); + this.setDataChannels(in.readInt()); + this.setDataFileSeq(in.readShort()); + this.setDataBitsPerSample(in.readShort()); + this.setDataRecords(in.readInt()); + this.setDataDomain(in.readShort()); + this.setDataType(in.readShort()); + this.setDataSampleRate(in.readInt()); + for (int i = 0; i < header.reserved.length; i++) + header.reserved[i] = in.readShort(); + for (int i = 0; i < header.numerical.length; i++) + header.numerical[i] = in.readDouble(); + in.read(header.asm_id_string); + in.read(header.signal_name); + in.read(header.user_text); + in.read(header.date); + in.read(header.description); + int length = this.getDataLength()*this.getDataRecords()*this.getDataChannels(); + if (this.getDataType() == REAL || this.getDataType() == COMP) { + double[] real_data = new double[length]; + for (int i = 0; i < length; i++) { + real_data[i] = in.readDouble(); + } + this.setRealData(real_data); + } + if (this.getDataType() == IMAG || this.getDataType() == COMP) { + double[] imag_data = new double[length]; + for (int i = 0; i < length; i++) { + imag_data[i] = in.readDouble(); + } + this.setImagData(imag_data); + } + if (this.getDataType() == REAL) { + double[] imag_data = new double[length]; + this.setImagData(imag_data); + } + if (this.getDataType() == IMAG) { + double[] real_data = new double[length]; + this.setRealData(real_data); + } + } + } +} diff --git a/asm/src/signals/SignalWindow.java b/asm/src/signals/SignalWindow.java new file mode 100644 index 0000000..07d2475 --- /dev/null +++ b/asm/src/signals/SignalWindow.java @@ -0,0 +1,1221 @@ +package signals; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Map; + +import console.CommandLineParser; +import dialogs.SaveSignalDialog; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.stage.Stage; + +public class SignalWindow { + + public static final int SIGNAL_HOOGTE = 250; /* Aantal pixels verticaal voor signaal */ + public static final int BODE_SIGNAL_HOOGTE = 200; /* Aantal pixels verticaal voor signaal */ + public static final double PH_MAG = 3.0; /* Verhouding tussen phase/magn bij bodediagram */ + public static final int LEFT_XOFFS = 100; /* Marge links */ + public static final int RIGHT_XOFFS = 50; /* Marge rechts */ + public static final int BOTTEM_YOFFS = 50; /* Marge onder */ + public static final int TOP_YOFFS = 50; /* Marge boven */ + public static final double PIXEL_DIST = 100.0; + public static final int USHRT_MAX = 65535; + public static final int PHASE_MAX = 200; + public static final int PHASE_MIN = -200; + + private final Signal signal; + private final MenuBar menuBar; + private final Canvas canvas; + private final GraphicsContext gc; + private final Stage stage = new Stage(); + private boolean bon = false; + + public SignalWindow(Signal s, CommandLineParser parser, Map signals) { + this.signal = s; + this.signal.setWindow(this); + + menuBar = new MenuBar(); + Menu menuFile = new Menu("File"); + MenuItem menuItemSave = new MenuItem("Save"); + menuFile.getItems().add(menuItemSave); + + Menu menuView = new Menu("View"); + MenuItem menuItemConsole = new MenuItem("Console"); + menuView.getItems().add(menuItemConsole); + + menuItemSave.setOnAction(e -> { + new SaveSignalDialog(parser, signals, s.getName()); + }); + menuItemConsole.setOnAction(e -> { + parser.showConsole(); + }); + menuBar.getMenus().add(menuFile); + menuBar.getMenus().add(menuView); + + canvas = new Canvas(signal.getWindowWidth(), signal.getWindowHeight()); + gc = canvas.getGraphicsContext2D(); + this.show(bon); + } + + public void show(boolean bon) { + this.bon = bon; + String mode; + switch (signal.getMode()) { + case Signal.REAL_M: + mode = " Real"; + break; + case Signal.IMAG_M: + mode = " Imaginary"; + break; + case Signal.MAGN_M: + mode = " Magnitude"; + break; + case Signal.BODE_M: + mode = " Bode"; + break; + case Signal.PHAS_M: + mode = " Phase"; + break; + default: + mode = ""; + break; + } + switch (signal.getDataDomain()) { + case Signal.TIME: + mode += " (Time)"; + break; + case Signal.FREQ: + mode += " (Frequency)"; + break; + default: + break; + } + + VBox root = new VBox(); + + signal.setWindowWidth((int) (signal.getHScale() * signal.getDataLength() + LEFT_XOFFS + RIGHT_XOFFS)); + if (signal.getMode() == Signal.BODE_M) { + signal.setWindowHeight( + BODE_SIGNAL_HOOGTE + (int) (BODE_SIGNAL_HOOGTE / PH_MAG) + 2 * TOP_YOFFS + BOTTEM_YOFFS); + } else { + signal.setWindowHeight(SIGNAL_HOOGTE + TOP_YOFFS + BOTTEM_YOFFS); + } + // TODO : get actual height of menu bar. + // menuBar.getheight() returns 0.0. Now adding 50. + Scene scene = new Scene(root, signal.getWindowWidth(), signal.getWindowHeight() + 50); + canvas.setWidth(signal.getWindowWidth()); + canvas.setHeight(signal.getWindowHeight()); + root.getChildren().add(menuBar); + root.getChildren().add(canvas); + + gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); + + switch (this.signal.getMode()) { + case Signal.REAL_M: + case Signal.IMAG_M: + if (this.signal.getDataDomain() == Signal.TIME) + genSignalBackground(this.signal, gc); + if (this.signal.getDataDomain() == Signal.FREQ) + gen_freq_background(this.signal, gc); + genSignalPlot(this.signal, gc); + break; + case Signal.BODE_M: + genBodeBackground(this.signal, gc); + genBodePlot(this.signal, gc); + break; + case Signal.MAGN_M: + gen_magnitude_background(this.signal, gc); + gen_magnitude_plot(this.signal, gc); + break; + case Signal.PHAS_M: + gen_phase_background(this.signal, gc); + gen_phase_plot(this.signal, gc); + break; + case Signal.HIST_M: + gen_hist_background(this.signal, gc); + gen_hist_plot(this.signal, gc); + break; + default: + break; + } + + stage.setScene(scene); + stage.setTitle("Signal " + this.signal.getName() + " " + mode); + stage.show(); + } + + public void close() { + stage.close(); + } + + private double getRecordMax(Signal s) { + int offset = (s.getChannel()*s.getDataRecords() +s.getRecord())*s.getDataLength(); + double[] data = (s.getMode() == Signal.IMAG_M) ? s.getImagData() : s.getRealData(); + double max = data[offset]; + for (int i = 1; i < s.getDataLength(); i++) { + if (data[offset+i] > max) + max = data[offset+i]; + } + return max; + } + + private double getRecordMin(Signal s) { + int offset = (s.getChannel()*s.getDataRecords() +s.getRecord())*s.getDataLength(); + double[] data = (s.getMode() == Signal.IMAG_M) ? s.getImagData() : s.getRealData(); + double min = data[offset]; + for (int i = 1; i < s.getDataLength(); i++) { + if (data[offset+i] < min) + min = data[offset+i]; + } + return min; + } + + private void genSignalBackground(Signal s, GraphicsContext gc) { + int length = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; + int maxy = s.getWindowHeight(); + int height = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; + double distance = PIXEL_DIST; + + int aantaltxt = (int) ((length / distance) + 1); + double totalTime = (double) s.getDataLength() / (double) (s.getDataSampleRate() * 10); + double deltaT = totalTime / (double) (aantaltxt - 1); + distance = (double) length / (double) (aantaltxt - 1); + + double unit = 1.0; + char eenhstr = ' '; + + if (totalTime < (1.0)) { + unit = 1e-3; + eenhstr = 'm'; + } + if (totalTime < (1e-3)) { + unit = 1e-6; + eenhstr = 'u'; + } + if (totalTime < (1e-6)) { + unit = 1e-9; + eenhstr = 'n'; + } + if (totalTime < (1e-9)) { + unit = 1e-11; + eenhstr = 'p'; + } + + gc.setStroke(Color.GRAY); + double fontHeight = gc.getFont().getSize(); + gc.strokeText("--> Time [" + eenhstr + "s]", length / 2, maxy - fontHeight); + + deltaT = deltaT / unit; + + /* print 0 x-as, y-as text */ + + gc.strokeText("0", LEFT_XOFFS, maxy - 28); + + /* print record_nr en channel_nr */ + + String ch = String.format("Rec: %d - Chan: %d", s.getRecord(), s.getChannel()); + gc.strokeText(ch, (LEFT_XOFFS + length - 200), (TOP_YOFFS - 10)); + + for (int i = 1; i < aantaltxt; i++) { + double xwaarde = (deltaT * i); + ch = String.format("%3.2f", xwaarde); + gc.strokeText(ch, (int) (i * distance + LEFT_XOFFS - 25), (int) (maxy - 28)); + } + + /* draw vertical grid */ + gc.setStroke(Color.GRAY); + for (int i = 1; i < aantaltxt; i++) + gc.strokeLine(LEFT_XOFFS + i * distance, (TOP_YOFFS), LEFT_XOFFS + i * distance, (height + TOP_YOFFS)); + + /* draw the x en y axis in black (+ up and right) */ + gc.setStroke(Color.BLACK); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(length + LEFT_XOFFS, TOP_YOFFS, length + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, (maxy - BOTTEM_YOFFS), length + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, length + LEFT_XOFFS, TOP_YOFFS); + + double[] data; + + if (s.getMode() == Signal.REAL_M) { + data = s.getRealData(); /* display real data */ + } else { + data = s.getImagData(); /* display imaginary data */ + } + + double Minimum = getRecordMin(s); + double Maximum = getRecordMax(s); + if ((Maximum <= 1) && (Maximum >= 0.0)) + Maximum = 1; + if ((Minimum >= -1) && (Minimum <= 0.0)) + Minimum = -1; + + s.setMinimum(Minimum); + s.setMaximum(Maximum); + + aantaltxt = 9; + distance = (int) (-height / (aantaltxt - 1)); + + double Max_abs = (double) Math.max(Math.abs(Maximum), Math.abs(Minimum)); /* Absolute maximum */ + double deltaY = Max_abs * 2 / (aantaltxt - 1); + s.setVScale(Max_abs / (height / 2.0)); + + gc.setStroke(Color.GRAY); + if (Max_abs >= USHRT_MAX) { + for (int tel = 0; tel < aantaltxt; tel++) { + double y_waarde = Max_abs - deltaY * tel; + ch = String.format("%8.2g", y_waarde); + gc.strokeText(ch, (LEFT_XOFFS - 95), (int) -(tel * distance - TOP_YOFFS - 5)); + } + } + + if (Max_abs < USHRT_MAX) { + for (int tel = 0; tel < aantaltxt; tel++) { + double y_waarde = Max_abs - deltaY * tel; + ch = String.format("%5.2f", y_waarde); + gc.strokeText(ch, (LEFT_XOFFS - 95), (int) -(tel * distance - TOP_YOFFS - 5)); + } + } + + gc.setStroke(Color.BLACK); + for (int i = 1; i < aantaltxt - 1; i++) + gc.strokeLine(LEFT_XOFFS + 1, (int) -(i * distance - TOP_YOFFS), length + LEFT_XOFFS - 1, + (int) -(i * distance - TOP_YOFFS)); + } + + private void gen_freq_background(Signal s, GraphicsContext gc) { + int lengte, hoogte, aantaltxt, sampler; + double delta_f, delta_y, Max_abs; + double eenheid, afstand; + + String nm = "Signal " + s.getName(); + + if (s.getMode() == Signal.REAL_M) + nm += " Real (Freq)"; + else + nm += " Imaginary (Freq)"; + + lengte = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; /* Lengte horizontale as */ + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; /* Lengte verticale as */ + afstand = PIXEL_DIST; /* Aantal pixels tussen twee getallen */ + sampler = s.getDataSampleRate() * 10; /* Samplerate in Hz */ + int maxy = s.getWindowHeight(); + + gc.setStroke(Color.RED); + double fontHeight = gc.getFont().getSize(); + gc.strokeText(nm, (lengte / 2), fontHeight); + + aantaltxt = (int) ((lengte / afstand) + 1); /* Aantal getallen horizontale as */ + delta_f = (double) (sampler) / (double) (aantaltxt - 1); /* freq tussen twee getallen */ + afstand = (double) (lengte) / (double) (aantaltxt - 1); /* Aantal pixels tussen twee getallen */ + + eenheid = 1e3; /* Kies voor de eenheid 1000 (kHz) */ + delta_f = delta_f / eenheid; + + gc.setStroke(Color.GRAY); + gc.strokeText("--> Frequency [kHz]", (lengte / 2), maxy - fontHeight); + + /* print 0 x-as text */ + gc.strokeText("0", LEFT_XOFFS, maxy - 28); + + /* allocate data for xwaarde */ + for (int tel = 1; tel < aantaltxt; tel++) { + double xwaarde = delta_f * tel; + gc.strokeText(String.format("%3.2f", xwaarde), (int) (tel * afstand + LEFT_XOFFS - 25), (int) (maxy - 28)); + } + + /* print record_nr en channel_nr */ + String ch = String.format("Rec: %d - Chan: %d", s.getRecord(), s.getChannel()); + gc.strokeText(ch, LEFT_XOFFS + lengte - 200, TOP_YOFFS - 10); + + /* teken vertikaal grid */ + for (int tel = 1; tel < aantaltxt; tel++) + gc.strokeLine(LEFT_XOFFS + tel * afstand, TOP_YOFFS, LEFT_XOFFS + tel * afstand, hoogte + TOP_YOFFS); + + /* teken de x en y as in zwart (+ boven en rechts) */ + gc.setStroke(Color.BLACK); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(lengte + LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, (maxy - BOTTEM_YOFFS), lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, TOP_YOFFS); + + double[] data; + /* Bepaal VSCALE m.b.v. Maximum en minimum */ + if (s.getMode() == Signal.REAL_M) { + data = s.getRealData(); /* display real data */ + } else { + data = s.getImagData(); /* display imaginary data */ + } + + int offset = s.getRecord() * s.getDataLength(); + double Minimum = getRecordMin(s); + double Maximum = getRecordMax(s); + + s.setMaximum(Maximum); + s.setMinimum(Minimum); + + aantaltxt = 9; + afstand = (int) (-hoogte / (aantaltxt - 1)); + + Max_abs = (double) Math.max(Math.abs(Maximum), Math.abs(Minimum)); /* Absolute maximum */ + if (Max_abs == 0.0) + Max_abs = 1; + delta_y = Max_abs * 2 / (aantaltxt - 1); + + s.setVScale(Max_abs / (hoogte / 2)); + + gc.setStroke(Color.GRAY); + if (Max_abs >= USHRT_MAX) { + for (int tel = 0; tel < aantaltxt; tel++) { + double y_waarde = (int) (Max_abs - delta_y * tel); + ch = String.format("%8.2g", y_waarde); + gc.strokeText(ch, (LEFT_XOFFS - 95), (int) -(tel * afstand - TOP_YOFFS - 5)); + } + } + + if (Max_abs < USHRT_MAX) { + for (int tel = 0; tel < aantaltxt; tel++) { + double y_waarde = Max_abs - delta_y * tel; + ch = String.format("%5.2f", y_waarde); + gc.strokeText(ch, (LEFT_XOFFS - 95), (int) -(tel * afstand - TOP_YOFFS - 5)); + } + } + + gc.setStroke(Color.BLACK); + for (int tel = 1; tel < aantaltxt - 1; tel++) + + gc.strokeLine(LEFT_XOFFS + 1, (int) -(tel * afstand - TOP_YOFFS), lengte + LEFT_XOFFS - 1, + (int) -(tel * afstand - TOP_YOFFS)); + } + + private void genSignalPlot(Signal s, GraphicsContext gc) { + int nul_offs, hoogte, x1, x2, y1, y2; + double vscale, hscale; + double[] data; /* pointer to data to display */ + double[] temp; /* temporary copy for scaling */ + + vscale = s.getVScale(); + hscale = s.getHScale(); + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; + + temp = new double[s.getDataLength()]; + + data = s.getRealData(); /* display real data */ + + if (s.getMode() == Signal.IMAG_M) { + data = s.getImagData(); /* display imaginary data */ + } + + /* Which record to display? */ + + int offset = (s.getChannel() * s.getDataRecords() + s.getRecord()) * s.getDataLength(); + + // System.out.println(String.format("Signal %s, Channel %d, Record + // %d\n",s.getName(),s.getChannel(),s.getRecord())); + + for (int i = 0; i < s.getDataLength(); i++) { + temp[i] = data[offset + i]; + } + + for (int i = 0; i < s.getDataLength(); i++) { + temp[i] = (temp[i] / vscale); + } + switch (s.getDataDomain()) { + case Signal.TIME: + gc.setStroke(Color.RED); + nul_offs = hoogte / 2 + TOP_YOFFS; + + if (!bon) { + for (int i = 0; i < s.getDataLength() - 1; i++) { + x1 = (int) (hscale * i + LEFT_XOFFS); + x2 = (int) (hscale * (i + 1) + LEFT_XOFFS); + y1 = (int) -(temp[i] - nul_offs); + y2 = (int) -(temp[i + 1] - nul_offs); + // System.out.println(String.format(" %d %d %d %d",x1,y1,x2,y2)); + gc.strokeLine(x1, y1, x2, y2); + } + } else { + for (int i = 0; i < s.getDataLength(); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (nul_offs), (int) (hscale * i + LEFT_XOFFS), + (int) -(temp[i] - nul_offs)); + } + } + break; + + case Signal.FREQ: + gc.setStroke(Color.GREEN); + nul_offs = (int) (TOP_YOFFS + (s.getMaximum() / s.getVScale())); + + if (!bon) { + for (int i = 0; i < (s.getDataLength() - 1); i++) { + x1 = (int) (hscale * i + LEFT_XOFFS); + x2 = (int) (hscale * (i + 1) + LEFT_XOFFS); + gc.strokeLine(x1, (int) -(temp[i] - nul_offs), x2, (int) -(temp[i + 1] - nul_offs)); + } + } else + for (int i = 0; i < (s.getDataLength()); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (nul_offs), (int) (hscale * i + LEFT_XOFFS), + (int) -(temp[i] - nul_offs)); + } + + break; + case Signal.MAGN: + gc.setStroke(Color.RED); + nul_offs = hoogte / 2 + TOP_YOFFS; + + if (!bon) { + for (int i = 0; i < (s.getDataLength() - 1); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) -(temp[i] - nul_offs), + (int) (hscale * (i + 1) + LEFT_XOFFS), (int) -(temp[i + 1] - nul_offs)); + } + } else { + for (int i = 0; i < (s.getDataLength()); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (nul_offs), (int) (hscale * i + LEFT_XOFFS), + (int) -(temp[i] - nul_offs)); + } + } + break; + + default: + break; + } + + } + + private void genBodeBackground(Signal s, GraphicsContext gc) { + int magHeight, phaseHeight, nrOfText, sampler; + int mag_top_offs; + int delta_ph; + double deltaFreq, delta_db, Max_abs; + double unit, distance; + + String nm = "Signal " + s.getName() + " BodeDiagram"; + + magHeight = BODE_SIGNAL_HOOGTE; + phaseHeight = (int) (BODE_SIGNAL_HOOGTE / PH_MAG); + mag_top_offs = phaseHeight + 2 * TOP_YOFFS; + + int length = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; /* Length horizontal axis */ + int maxy = s.getWindowHeight(); + /* Horizontal axis + text */ + gc.setStroke(Color.RED); + double fontHeight = gc.getFont().getSize(); + gc.strokeText(nm, length / 2, fontHeight); + + distance = PIXEL_DIST; /* Nr of pixels between two numbers */ + sampler = s.getDataSampleRate() * 10; /* Sample rate in Hz */ + + nrOfText = (int) ((length / distance) + 1); /* Nr of numbers horizontal axis */ + deltaFreq = (double) (sampler) / (double) (nrOfText - 1); /* freq between two numbers */ + distance = (double) (length) / (double) (nrOfText - 1); /* Nr of pixels between two numbers */ + + unit = 1e3; /* Choose unit 1000(kHz) */ + deltaFreq = deltaFreq / unit; + + gc.setStroke(Color.GRAY); + gc.strokeText("--> Frequency [kHz]", length / 2, maxy - fontHeight); + + // print 0 x-as text + gc.strokeText("0", LEFT_XOFFS, maxy - 28); + + // allocate data for x value + for (int i = 1; i < nrOfText; i++) { + double xValue = (deltaFreq * i); + String ch = String.format("%3.2f", xValue); + gc.strokeText(ch, (int) (i * distance + LEFT_XOFFS - 25), (int) (maxy - 28)); + } + + // print record_nr and channel_nr + String ch = String.format(" Chan: %d", s.getChannel()); + gc.strokeText(ch, LEFT_XOFFS + length - 200, TOP_YOFFS - 10); + + // draw vertical grid + gc.setStroke(Color.BLACK); + for (int tel = 1; tel < nrOfText; tel++) { + gc.strokeLine(LEFT_XOFFS + tel * distance, (TOP_YOFFS), LEFT_XOFFS + tel * distance, + (phaseHeight + TOP_YOFFS)); + gc.strokeLine(LEFT_XOFFS + tel * distance, (mag_top_offs), LEFT_XOFFS + tel * distance, + (mag_top_offs + magHeight)); + } + + // draw the x and y axis in black (+ up and right) + gc.strokeLine(LEFT_XOFFS, mag_top_offs, LEFT_XOFFS, (maxy - BOTTEM_YOFFS)); + gc.strokeLine(length + LEFT_XOFFS, mag_top_offs, length + LEFT_XOFFS, (maxy - BOTTEM_YOFFS)); + gc.strokeLine(LEFT_XOFFS, maxy - BOTTEM_YOFFS, length + LEFT_XOFFS, (maxy - BOTTEM_YOFFS)); + gc.strokeLine(LEFT_XOFFS, mag_top_offs, length + LEFT_XOFFS, mag_top_offs); + + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, LEFT_XOFFS, TOP_YOFFS + phaseHeight); + gc.strokeLine(length + LEFT_XOFFS, TOP_YOFFS, length + LEFT_XOFFS, TOP_YOFFS + phaseHeight); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, length + LEFT_XOFFS, TOP_YOFFS); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS + phaseHeight, length + LEFT_XOFFS, TOP_YOFFS + phaseHeight); + + // Determine VSCALE w.r.t. Maximum and minimum for the phase + s.setMaximum(PHASE_MAX); + s.setMinimum(PHASE_MIN); + + Max_abs = s.getMaximum() - s.getMinimum(); // difference between minimum and maximum + nrOfText = 5; + distance = (int) (-phaseHeight / (nrOfText - 1)); + delta_ph = (int) (Max_abs / (nrOfText - 1)); // delta is 20 degrees + + s.setVScale(Max_abs / (double) (phaseHeight)); + // System.out.println(String.format("MA: %g,phase_hoogte %d, Window_V: + // %g\n",Max_abs,phaseHeight,s.getVScale())); + + gc.setStroke(Color.GRAY); + for (int i = 0; i < nrOfText; i++) { + int ph = (int) (s.getMaximum() - delta_ph * i); + ch = String.format("%7d", ph); + gc.strokeText(ch, (LEFT_XOFFS - 80), (int) -(i * distance - TOP_YOFFS - 5)); + } + + gc.strokeText("Degrees", (LEFT_XOFFS), (TOP_YOFFS - 10)); + + gc.setStroke(Color.BLACK); + for (int i = 1; i < nrOfText - 1; i++) { + gc.strokeLine(LEFT_XOFFS + 1, -(i * distance - TOP_YOFFS), length + LEFT_XOFFS - 1, + -(i * distance - TOP_YOFFS)); + } + + // Determine VSCALE w.r.t. Maximum and minimum for magnitude + double[] real_data = s.getRealData(); // display real data + double[] imag_data = s.getImagData(); // display imaginary data + + double[] temp = new double[s.getDataLength()]; + for (int i = 0; i < s.getDataLength(); i++) { + temp[i] = 10.0 * Math.log10(Math.sqrt(Math.pow(real_data[i], 2.0) + Math.pow(imag_data[i], 2.0))); + } + + double Minimum, Maximum; /* min and max values of a record */ + Minimum = Maximum = temp[0]; // Determine Min and Max + + for (int i = 0; i < s.getDataLength(); i++) { + if (temp[i] > Maximum) + Maximum = temp[i]; + if (temp[i] < Minimum) + Minimum = temp[i]; + } + // Cut very low values at -100 dB. + if (Minimum < -100.0) { + Minimum = -100.0; + } + + s.setMaximum(((int) (Maximum / 10.0) + 1.0) * 10.0); + s.setMinimum(((int) (Minimum / 10.0) - 1.0) * 10.0); + + Max_abs = s.getMaximum() - s.getMinimum(); // difference minimum and maximum + nrOfText = (int) (Max_abs / 10.0) + 1; + distance = -magHeight / (nrOfText - 1); + delta_db = 10; + + s.setVScale(Max_abs / (magHeight)); + //System.out.println(String.format("max %f min %f, vscale %f", s.getMaximum(), s.getMinimum(),s.getVScale())); + //System.out.println(String.format("Max_abs %f", Max_abs)); + + gc.setStroke(Color.GRAY); + for (int i = 0; i < nrOfText; i++) { + int yValue = (int) (s.getMaximum() - delta_db * i); + ch = String.format("%7d", yValue); + gc.strokeText(ch, (LEFT_XOFFS - 80), (int) -(i * distance - mag_top_offs - 5)); + } + + gc.strokeText("dB", (LEFT_XOFFS), (mag_top_offs - 10)); + + gc.setStroke(Color.BLACK); + for (int tel = 1; tel < nrOfText - 1; tel++) { + gc.strokeLine(LEFT_XOFFS + 1, -(tel * distance - mag_top_offs), length + LEFT_XOFFS - 1, + -(tel * distance - mag_top_offs)); + } + + } + + private void genBodePlot(Signal s, GraphicsContext gc) { + int nul_offs, hoogte, phase_hoogte, mag_top_offs, Max_abs; + int x1, y1, x2, y2; + int data_nr, offs; + double hscale; + + hscale = s.getHScale(); + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; + int mid_type = s.getAverageType(); + + phase_hoogte = (int) (BODE_SIGNAL_HOOGTE / PH_MAG); + mag_top_offs = phase_hoogte + 2 * TOP_YOFFS; + + // generate magnitude part + + double[] real_data = s.getRealData(); + double[] imag_data = s.getImagData(); + + offs = s.getChannel() * s.getDataRecords() * s.getDataLength(); + + // System.out.println(String.format("Signal %s, Channel + // %d\n",s.getName(),s.getChannel())); + + double[] cum1 = new double[s.getDataLength()]; + double[] cum2 = new double[s.getDataLength()]; + + if (mid_type == 0) { + for (int j = 0; j < s.getDataRecords(); j++) { + for (int i = 0; i < s.getDataLength(); i++) { + data_nr = offs + i + j * s.getDataLength(); + // magnitude + double temp = Math.sqrt(Math.pow(real_data[data_nr], 2) + Math.pow(imag_data[data_nr], 2)); + /* Tel de magnitudes bij elkaar op */ + cum1[i] = cum1[i] + temp; + } + } + + for (int i = 0; i < s.getDataLength(); i++) { + cum1[i] = 10.0 * Math.log10(cum1[i] / s.getDataRecords()); + // Cut very low values at -100 dB. + if (cum1[i] < -100.0) + cum1[i] = -100.0; + cum1[i] = cum1[i]/ s.getVScale(); + } + } + + if (mid_type == 1) { + for (int j = 0; j < s.getDataRecords(); j++) + for (int i = 0; i < s.getDataLength(); i++) { + /* Tel de records bij elkaar op */ + cum1[i] = cum1[i] + (real_data[offs + i + j * s.getDataLength()]); + cum2[i] = cum2[i] + (imag_data[offs + i + j * s.getDataLength()]); + } + for (int i = 0; i < s.getDataLength(); i++) { + /* Deel door het aantal records */ + cum1[i] = cum1[i] / (double) (s.getDataRecords()); + cum2[i] = cum2[i] / (double) (s.getDataRecords()); + cum1[i] = 10 * Math.log10(Math.sqrt(Math.pow(cum1[i], 2) + Math.pow(cum2[i], 2))); + // Cut very low values at -100 dB. + if (cum1[i] < -100.0) + cum1[i] = -100.0; + cum1[i] = cum1[i]/ s.getVScale(); + } + + } + + nul_offs = (int) (mag_top_offs + (s.getMaximum() / s.getVScale())); + + gc.setStroke(Color.GREEN); + if (!bon) { + for (int i = 0; i < (s.getDataLength() - 1); i++) { + x1 = (int) (hscale * i + LEFT_XOFFS); + y1 = (int) -(cum1[i] - nul_offs); + x2 = (int) (hscale * (i + 1) + LEFT_XOFFS); + y2 = (int) -(cum1[i + 1] - nul_offs); + gc.strokeLine(x1, y1, x2, y2); + } + } else { + for (int i = 0; i < (s.getDataLength()); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (hoogte + TOP_YOFFS), + (int) (hscale * i + LEFT_XOFFS), (int) -(cum1[i] - nul_offs)); + } + } + + /* genereer phase gedeelte */ + + s.setMaximum(PHASE_MAX); + s.setMinimum(PHASE_MIN); + + Max_abs = (int) (s.getMaximum() - s.getMinimum()); /* verschil tussen minimum en maximum */ + s.setVScale(Max_abs / (double) (phase_hoogte)); + + //System.out.println(String.format("Max: %d , Vscale: %f , ph_h %d \n", Max_abs, s.getVScale(), phase_hoogte)); + + for (int i = 0; i < s.getDataLength(); i++) + cum1[i] = 0; + + if (mid_type == 0) { + for (int j = 0; j < s.getDataRecords(); j++) { + for (int i = 0; i < s.getDataLength(); i++) { + data_nr = offs + i + j * s.getDataLength(); + double temp = (180.0 / Math.PI) * Math.atan2(imag_data[data_nr], real_data[data_nr]); + cum1[i] = cum1[i] + temp; + } + } + + for (int i = 0; i < s.getDataLength(); i++) + cum1[i] = (cum1[i] / s.getDataRecords()) / s.getVScale(); + + } + + if (mid_type == 1) { + for (int j = 0; j < s.getDataRecords(); j++) + for (int i = 0; i < s.getDataLength(); i++) { + double temp = (real_data[offs + i + j * s.getDataLength()]); + cum1[i] = cum1[i] + temp; + temp = (imag_data[offs + i + j * s.getDataLength()]); + cum2[i] = cum2[i] + temp; + } + for (int i = 0; i < s.getDataLength(); i++) { + cum1[i] = cum1[i] / s.getDataRecords(); + cum2[i] = cum2[i] / s.getDataRecords(); + + cum1[i] = (180.0 / Math.PI) * Math.atan2(cum2[i], cum1[i]) / s.getVScale(); + } + + } + + nul_offs = (int) (TOP_YOFFS + (s.getMaximum() / s.getVScale())); + + if (!bon) { + for (int i = 0; i < (s.getDataLength() - 1); i++) { + x1 = (int) (hscale * i + LEFT_XOFFS); + y1 = (int) -(cum1[i] - nul_offs); + x2 = (int) (hscale * (i + 1) + LEFT_XOFFS); + y2 = (int) -(cum1[i + 1] - nul_offs); + gc.strokeLine(x1, y1, x2, y2); + } + } else { + for (int i = 0; i < (s.getDataLength()); i++) { + x1 = (int) (hscale * i + LEFT_XOFFS); + y1 = (int) (nul_offs); + x2 = (int) (hscale * i + LEFT_XOFFS); + y2 = (int) -(cum1[i] - nul_offs); + gc.strokeLine(x1, y1, x2, y2); + } + } + } + + private void gen_magnitude_background(Signal s, GraphicsContext gc) { + int lengte, hoogte, aantaltxt, sampler; + double delta_f, delta_db, Max_abs; + double eenheid, afstand; + double Minimum, Maximum; /* min en max waarden van record */ + + String nm = "Signal " + s.getName() + " Magnitude (Freq)"; + + lengte = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; /* Lengte horizontale as */ + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; /* Lengte verticale as */ + int maxy = s.getWindowHeight(); + gc.setStroke(Color.RED); + double fontHeight = gc.getFont().getSize(); + gc.strokeText(nm, (lengte / 2), fontHeight); + + afstand = PIXEL_DIST; /* Aantal pixels tussen twee getallen */ + sampler = s.getDataSampleRate() * 10; /* Samplerate in Hz */ + + aantaltxt = (int) ((lengte / afstand) + 1); /* Aantal getallen horizontale as */ + delta_f = (double) (sampler) / (double) (aantaltxt - 1); /* freq tussen twee getallen */ + afstand = (double) (lengte) / (double) (aantaltxt - 1); /* Aantal pixels tussen twee getallen */ + + eenheid = 1e3; /* Kies voor de eenheid 1000 (kHz) */ + delta_f = delta_f / eenheid; + + gc.setStroke(Color.GRAY); + gc.strokeText("--> Frequency [kHz]", (lengte / 2), maxy - fontHeight); + + /* print 0 x-as text */ + gc.strokeText("0", LEFT_XOFFS, maxy - 28); + + for (int tel = 1; tel < aantaltxt; tel++) { + double xwaarde = (delta_f * tel); + String ch = String.format("%3.2f", xwaarde); + gc.strokeText(ch, (int) (tel * afstand + LEFT_XOFFS - 25), (int) (maxy - 28)); + } + + /* print record_nr en channel_nr */ + + String ch = String.format(" Chan: %d", s.getChannel()); + gc.strokeText(ch, LEFT_XOFFS + lengte - 200, TOP_YOFFS - 10); + + // teken vertikaal grid + for (int tel = 1; tel < aantaltxt; tel++) + gc.strokeLine(LEFT_XOFFS + tel * afstand, TOP_YOFFS, LEFT_XOFFS + tel * afstand, hoogte + TOP_YOFFS); + + /* teken de x en y as in zwart (+ boven en rechts) */ + gc.setStroke(Color.BLACK); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(lengte + LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, maxy - BOTTEM_YOFFS, lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, TOP_YOFFS); + + /* Bepaal VSCALE m.b.v. Maximum en minimum */ + + double[] real_data = s.getRealData(); /* display real data */ + double[] imag_data = s.getImagData(); /* display imaginary data */ + int dataLength = s.getDataLength(); + double[] temp = new double[dataLength]; + + if (s.getLog() == 1) + for (int tel = 0; tel < dataLength; tel++) { + temp[tel] = 10 * Math.log10(Math.sqrt(Math.pow(real_data[tel], 2) + Math.pow(imag_data[tel], 2))); + } + else + for (int tel = 0; tel < dataLength; tel++) { + temp[tel] = (Math.sqrt(Math.pow(real_data[tel], 2) + Math.pow(imag_data[tel], 2))); + } + + Minimum = Maximum = temp[0]; /* Min en Max bepalen */ + + for (int i = 1; i < dataLength; i++) { + if (temp[i] > Maximum) + Maximum = temp[i]; + if (temp[i] < Minimum) + Minimum = temp[i]; + } + if (s.getLog() == 1) { + // Cut very low values at -100 dB. + if (Minimum < -100.0) { + Minimum = -100.0; + } + } + + if (s.getLog() == 1) { + s.setMaximum(((int) (Maximum / 10) + 1) * 10); + s.setMinimum(((int) (Minimum / 10) - 1) * 10); + Max_abs = s.getMaximum() - s.getMinimum(); /* verschil tussen minimum en maximum */ + aantaltxt = (int) (Max_abs / 10) + 1; + delta_db = 10; + } else { + s.setMaximum(Maximum); + s.setMinimum(0); + if (s.getMaximum() <= 1) + s.setMaximum(1); + Max_abs = s.getMaximum(); + aantaltxt = 9; + delta_db = Max_abs / (aantaltxt - 1); + } + + afstand = -hoogte / (aantaltxt - 1); + + s.setVScale(Max_abs / (hoogte)); + + gc.setStroke(Color.GRAY); + for (int tel = 0; tel < aantaltxt; tel++) { + int ywaarde = (int) (s.getMaximum() - delta_db * tel); + ch = String.format("%7d", ywaarde); + gc.strokeText(ch, (LEFT_XOFFS - 80), (int) -(tel * afstand - TOP_YOFFS - 5)); + } + + if (s.getLog() == 1) { + gc.strokeText("dB", LEFT_XOFFS, TOP_YOFFS - 10); + } + + for (int tel = 1; tel < aantaltxt - 1; tel++) { + gc.strokeLine(LEFT_XOFFS + 1, -(tel * afstand - TOP_YOFFS), lengte + LEFT_XOFFS - 1, + -(tel * afstand - TOP_YOFFS)); + } + + } + + private void gen_magnitude_plot(Signal s, GraphicsContext gc) { + int nul_offs, hoogte; + double hscale; + + hscale = s.getHScale(); + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; + + double[] real_data = s.getRealData(); /* display real data */ + + /* Bereken het adres van het channel dat je wil zien. */ + + double temp[] = new double[s.getDataLength()]; + int offset = (s.getChannel() * s.getDataRecords() + s.getRecord()) * s.getDataLength(); + + /* + * asm_wprintf("Signal %s, Channel %d\n",DataSignalName(vp),Window_Channel(vp)); + */ + + if (s.getLog() == 1) { + for (int i = 0; i < s.getDataLength(); i++) { + temp[i] = (10 * Math.log10(real_data[offset + i])); + // Cut very low values at -100 dB. + if (temp[i] < -100.0) + temp[i] = -100.0; + temp[i] = temp[i]/ s.getVScale(); + } + } else { + for (int i = 0; i < s.getDataLength(); i++) + temp[i] = ((real_data[offset + i])) / s.getVScale(); + } + + nul_offs = (int) (TOP_YOFFS + (s.getMaximum() / s.getVScale())); + + gc.setStroke(Color.GREEN); + if (!bon) { + for (int i = 0; i < (s.getDataLength() - 1); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) -(temp[i] - nul_offs), + (int) (hscale * (i + 1) + LEFT_XOFFS), (int) -(temp[i + 1] - nul_offs)); + } + } else { + for (int i = 0; i < s.getDataLength(); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (hoogte + TOP_YOFFS), + (int) (hscale * i + LEFT_XOFFS), (int) -(temp[i] - nul_offs)); + } + } + } + + private void gen_phase_background(Signal s, GraphicsContext gc) { + int lengte, hoogte, aantaltxt, sampler; + double delta, delta_f, Max_abs; + double eenheid, afstand; + + String nm = "Signal " + s.getName() + " Phase"; + + lengte = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; /* Lengte horizontale as */ + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; /* Lengte verticale as */ + afstand = PIXEL_DIST; /* Aantal pixels tussen twee getallen */ + sampler = s.getDataSampleRate() * 10; /* Samplerate in Hz */ + int maxy = s.getWindowHeight(); + + gc.setStroke(Color.RED); + double fontHeight = gc.getFont().getSize(); + gc.strokeText(nm, (lengte / 2), fontHeight); + + aantaltxt = (int) ((lengte / afstand) + 1); /* Aantal getallen horizontale as */ + delta_f = (double) (sampler) / (double) (aantaltxt - 1); /* freq tussen twee getallen */ + afstand = (double) (lengte) / (double) (aantaltxt - 1); /* Aantal pixels tussen twee getallen */ + + eenheid = 1e3; /* Kies voor de eenheid 1000 (kHz) */ + delta_f = delta_f / eenheid; + + gc.setStroke(Color.GRAY); + gc.strokeText("--> Frequency [kHz]", (lengte / 2), maxy - fontHeight); + + /* print 0 x-as text */ + gc.strokeText("0", LEFT_XOFFS, maxy - 28); + + /* allocate data for xwaarde */ + for (int tel = 1; tel < aantaltxt; tel++) { + double xwaarde = (delta_f * tel); + String ch = String.format("%3.2f", xwaarde); + gc.strokeText(ch, (int) (tel * afstand + LEFT_XOFFS - 25), (int) (maxy - 28)); + } + + /* print record_nr en channel_nr */ + + String ch = String.format(" Chan: %d", s.getChannel()); + gc.strokeText(ch, (LEFT_XOFFS + lengte - 200), (TOP_YOFFS - 10)); + + /* teken vertikaal grid */ + for (int tel = 1; tel < aantaltxt; tel++) + gc.strokeLine(LEFT_XOFFS + tel * afstand, TOP_YOFFS, LEFT_XOFFS + tel * afstand, hoogte + TOP_YOFFS); + + /* teken de x en y as in zwart (+ boven en rechts) */ + gc.setStroke(Color.BLACK); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(lengte + LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, (maxy - BOTTEM_YOFFS), lengte + LEFT_XOFFS, maxy - BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS, TOP_YOFFS, lengte + LEFT_XOFFS, TOP_YOFFS); + + /* Bepaal VSCALE m.b.v. Maximum en minimum */ + + s.setMaximum(PHASE_MAX); + s.setMinimum(PHASE_MIN); + + Max_abs = s.getMaximum() - s.getMinimum(); /* verschil tussen minimum en maximum */ + aantaltxt = 11; + afstand = -hoogte / (aantaltxt - 1); + delta = Max_abs / (aantaltxt - 1); /* delta is 20 graden */ + + s.setVScale(Max_abs / hoogte); + + gc.setStroke(Color.GRAY); + for (int tel = 0; tel < aantaltxt; tel++) { + int ywaarde = (int) (s.getMaximum() - delta * tel); + ch = String.format("%7d", ywaarde); + gc.strokeText(ch, (LEFT_XOFFS - 80), (int) -(tel * afstand - TOP_YOFFS - 5)); + } + + gc.strokeText("Degrees", LEFT_XOFFS, TOP_YOFFS - 10); + + for (int tel = 1; tel < aantaltxt - 1; tel++) { + gc.strokeLine(LEFT_XOFFS + 1, -(tel * afstand - TOP_YOFFS), lengte + LEFT_XOFFS - 1, + -(tel * afstand - TOP_YOFFS)); + } + } + + private void gen_phase_plot(Signal s, GraphicsContext gc) { + int nul_offs; + double hscale; + + hscale = s.getHScale(); + double[] temp = new double[s.getDataRecords() * s.getDataLength()]; + double[] real_data = s.getRealData(); /* display real data */ + + /* + * Bereken het adres van het channel dat je wil zien. In het fase domein + * bevatten channels altijd maar 1 record + */ + + int offset = s.getChannel() * s.getRecord() * s.getDataLength(); + + // System.out.println(String.format("Signal: %s, Channel: + // %d\n",s.getName(),s.getChannel())); + // System.out.println(String.format("VSCALE : %g",s.getVScale())); + + for (int i = 0; i < s.getDataLength(); i++) + temp[i] = (real_data[i + offset]) / s.getVScale(); + + nul_offs = (int) (TOP_YOFFS + (s.getMaximum() / s.getVScale())); + + gc.setStroke(Color.GREEN); + if (!bon) { + for (int i = 0; i < s.getDataLength() - 1; i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) -(temp[i] - nul_offs), + (int) (hscale * (i + 1) + LEFT_XOFFS), (int) -(temp[i + 1] - nul_offs)); + } + } else { + for (int i = 0; i < s.getDataLength(); i++) { + gc.strokeLine((int) (hscale * i + LEFT_XOFFS), (int) (nul_offs), (int) (hscale * i + LEFT_XOFFS), + (int) -(temp[i] - nul_offs)); + } + } + } + + private void gen_hist_background(Signal s, GraphicsContext gc) + { + int lengte,hoogte,aantaltxt; + double delta_a,delta_n,Max_abs; + double xwaarde, afstand; + int maxy = s.getWindowHeight(); + + String nm = "Signal " + s.getName() + " Histogram (Time)"; + + lengte = s.getWindowWidth() - LEFT_XOFFS - RIGHT_XOFFS; /* Lengte horizontale as */ + hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; /* Lengte verticale as */ + afstand = PIXEL_DIST; /* Aantal pixels tussen twee getallen */ + + gc.setStroke(Color.RED); + double fontHeight = gc.getFont().getSize(); + gc.strokeText(nm, (lengte / 2), fontHeight); + + double min = getRecordMin(s); + double max = getRecordMax(s); + s.setMinimum(min); + s.setMaximum(max); + aantaltxt = (int) ((lengte/afstand)+1); /* Aantal getallen horizontale as */ + delta_a = (double)(max-min)/(double)(aantaltxt-1); /* ampl tussen twee getallen */ + afstand = (double)(lengte)/(double)(aantaltxt-1); /* Aantal pixels tussen twee getallen */ + + gc.setStroke(Color.GRAY); + gc.strokeText("--> Magnitude",(lengte/2),maxy-fontHeight); + + /* print 0 x-as text*/ + String ch = String.format("%5.1f", min); + gc.strokeText(ch,LEFT_XOFFS,maxy-28); + + + /* for(tel=1;tel < aantaltxt;tel++) + { + */ + int tel = aantaltxt -1; + + /* xwaarde[tel]=(delta_a*tel+DataRealMin(vp)); + sprintf(ch,"%5.1f",xwaarde[tel]); */ + + xwaarde=(delta_a*tel+min); + ch = String.format("%5.1f", xwaarde); + gc.strokeText(ch,(int)(tel*afstand+LEFT_XOFFS-25),(int)(maxy-28)); + + /* } */ + + + + /* print record_nr en channel_nr */ + + ch = String.format("Chan: %d", s.getChannel()); + gc.strokeText(ch,(LEFT_XOFFS+lengte-100),TOP_YOFFS-10); + + + /* teken vertikaal grid */ + + for(int i=1;i < aantaltxt;i++) + gc.strokeLine(LEFT_XOFFS+i*afstand, TOP_YOFFS, LEFT_XOFFS+i*afstand, hoogte+TOP_YOFFS); + + + /* teken de x en y as in zwart (+ boven en rechts) */ + gc.setStroke(Color.GRAY); + gc.strokeLine(LEFT_XOFFS , TOP_YOFFS , LEFT_XOFFS , maxy-BOTTEM_YOFFS); + gc.strokeLine(lengte+LEFT_XOFFS, TOP_YOFFS , lengte+LEFT_XOFFS , maxy-BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS , (maxy-BOTTEM_YOFFS), lengte+LEFT_XOFFS , maxy-BOTTEM_YOFFS); + gc.strokeLine(LEFT_XOFFS , TOP_YOFFS , lengte+LEFT_XOFFS , TOP_YOFFS); + + + /* Bepaal VSCALE m.b.v. Maximum en minimum */ + + + double[] real_data = s.getRealData(); /* display real data */ + + Max_abs = 100; /* verschil tussen minimum en maximum in % */ + aantaltxt = (int)11; + afstand = -hoogte/(aantaltxt-1); + delta_n = 10; + + s.setVScale(s.getMaximum()/hoogte); + + gc.setStroke(Color.GRAY); + for(int i=0;i < aantaltxt;i++) + { + int ywaarde=(int)(100-delta_n*i); + ch = String.format("%7d",ywaarde); + gc.strokeText(ch,(LEFT_XOFFS-80),(int)-(i*afstand-TOP_YOFFS-5)); + } + + gc.strokeText("%%", LEFT_XOFFS, TOP_YOFFS-10); + + for(tel=1;tel < aantaltxt-1;tel++) + { + gc.strokeLine(LEFT_XOFFS+1, -(tel*afstand-TOP_YOFFS), lengte+LEFT_XOFFS-1, -(tel*afstand-TOP_YOFFS)); + } + + } + + /************************************************************************** + * + * void gen_hist_plot(VENSTER *vp) + * + **************************************************************************/ + + private void gen_hist_plot(Signal s, GraphicsContext gc) + { + double vscale = s.getVScale(); + double hscale = s.getHScale(); + int hoogte = s.getWindowHeight() - TOP_YOFFS - BOTTEM_YOFFS; + + double[] cum = new double[s.getDataLength()]; + double[] data = s.getRealData(); /* display real data */ + + /* Welk record displayen? */ + + int offset = (s.getChannel()*s.getDataRecords()+s.getRecord())*s.getDataLength(); + + double[] temp = Arrays.copyOfRange(data, offset, offset+s.getDataLength()); + + cum[0]=temp[0]; + + for(int i=0; i < s.getDataLength();i++) + { + if (i > 0) + cum[i]=cum[i-1]+temp[i]; + temp[i]= (temp[i]/vscale); + } + + double cscale=cum[s.getDataLength()-1]/hoogte; + + int nul_offs = hoogte+TOP_YOFFS; + + gc.setStroke(Color.BLUE); + for(int i=0;i < s.getDataLength();i++) + { + gc.strokeLine((int)(hscale*i+LEFT_XOFFS), nul_offs, (int)(hscale*i+LEFT_XOFFS), (int)-(temp[i]-nul_offs)); + } + + gc.setStroke(Color.GREEN); + for(int i=0;i < (s.getDataLength()-1);i++) + { + gc.strokeLine((int)(hscale*i+LEFT_XOFFS), (int)-((cum[i]/cscale)-nul_offs), (int)(hscale*(i+1) + + LEFT_XOFFS), (int)-((cum[i+1]/cscale)-nul_offs)); + } + } + +} \ No newline at end of file diff --git a/asm/src/signals/Sources.java b/asm/src/signals/Sources.java new file mode 100644 index 0000000..9e0c1d1 --- /dev/null +++ b/asm/src/signals/Sources.java @@ -0,0 +1,660 @@ +package signals; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import console.CommandLineParser; + +public class Sources extends SourcesBase { + public static final double DEF_FREQ = 100.0; /* Default frequency */ + public static final double DEF_AMPL = 100.0; /* Default amplitude */ + private static final int RAND_MAX = 0x7fff; + public static final Map functions = new HashMap() { + { + put("fconstant", new String[]{"FconstCi", ""}); + put("fcosine", new String[]{"FcosineCi", ""}); + put("fdelta", new String[]{"FdeltaCi", ""}); + put("fexp", new String[]{"FexpCi", ""}); + put("fnoise", new String[]{"FnoiseCi", ""}); + put("framp", new String[]{"FrampCi", ""}); + put("fsinc", new String[]{"FsinecCi", ""}); + put("fsine", new String[]{"FsineCi", "fsine "}); + put("fsquare", new String[]{"FsquarewaveCi", ""}); + put("fstep", new String[]{"FstepCi", ""}); + put("ftriangle", new String[]{"FtriangleCi", ""}); + } + }; + + public Sources(Map signals, CommandLineParser cp) { + super(signals,cp); + } + + private void source(Signal s, List parameters) { + + int number = s.getDataLength(); + short dtype = s.getDataType(); + // Sources are always 1 channel, 1 record. + double[] real_data = new double[number]; + double[] imag_data = new double[number]; + s.setRealData(real_data); + s.setImagData(imag_data); + + Method method = null; + String methodName = s.getDataDescription(); + try { + method = this.getClass().getMethod(methodName, Signal.class, List.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return; + + try { + method.invoke(this, s, parameters); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + switch (dtype) { + case Signal.REAL: /* Real data */ + for (int i = 0; i < number; i++) { + imag_data[i] = 0; + } + s.setMode(Signal.REAL_M); + break; + case Signal.IMAG: /* Imaginary data */ + for (int i = 0; i < number; i++) { + real_data[i] = 0; + } + s.setMode(Signal.IMAG_M); + break; + case Signal.COMP: /* Complex data */ + for (int i = 0; i < number; i++) { + imag_data[i] = real_data[i]; + } + s.setMode(Signal.REAL_M); + break; + default: + s.setMode(Signal.REAL_M); + break; + } + } + + public static void constant(double[] data, double ampl) { + for (int i = 0; i < data.length; i++) { + data[i] = ampl; + } + } + + public void constant(Signal s, List parameters) { + double ampl = parameters.get(0); + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + constant(data, ampl); + } + + public Signal FconstCi(Signal s, List arguments) { + + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "constant"); + List parameters = new ArrayList(); + parameters.add(ampl); + + source(s, parameters); + return s; + } + + public static void delta(double data[], double ampl, double t0, double sampler) { + boolean flag = true; + for (int i = 0; i < data.length; i++) { + double t = (double) i / (double) sampler; + if (t < t0) + data[i] = (double) (0); + else if ((t >= t0) && flag) { + data[i] = ampl; + flag = false; + } else + data[i] = 0.0; + } + } + + public void delta(Signal s, List parameters) { + double ampl = parameters.get(0); + double t0 = parameters.get(1); + t0 = t0 / 1000.0; /* t0 in sec */ + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + delta(data, ampl, t0, sampler); + } + + public Signal FdeltaCi(Signal im, List arguments) { + + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double t0 = cp.getDouble(arguments, "Delta-t (millisec)", 0.0, Integer.MAX_VALUE, 0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(im, number, sample, dtype, "delta"); + List parameters = new ArrayList(); + parameters.add(ampl); + parameters.add(t0); + + source(im, parameters); + + return im; + } + + private static void step(double data[], double offs, double ampl, double t0, int sampler) { + double t; + for (int i = 0; i < data.length; i++) { + t = (double) i / (double) sampler; + if (t < t0) + data[i] = offs; + if (t >= t0) + data[i] = ampl + offs; + } + } + + public void step(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double t0 = parameters.get(2); + t0 = t0 / 1000.0; /* t0 in sec */ + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + step(data, offs, ampl, t0, sampler); + } + + public Signal FstepCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", 0.0, Integer.MAX_VALUE, 0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double t0 = cp.getDouble(arguments, "t-delay (millisec)", 0.0, Integer.MAX_VALUE, 0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "step"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(t0); + + source(s, parameters); + + return s; + } + + private static void noise(double data[], double ampl, int seed) { + Random rand = new Random(seed); + for (int i = 0; i < data.length; i++) { + data[i] = ampl / (RAND_MAX / 2.0) * (rand.nextInt(RAND_MAX) - (RAND_MAX / 2.0)); + } + } + + public void noise(Signal s, List parameters) { + double ampl = parameters.get(0); + int seed = parameters.get(1).intValue(); + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + noise(data, ampl, seed); + } + + public Signal FnoiseCi(Signal s, List arguments) { + + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + Integer seed = cp.getInt(arguments, "Seed <0 .. 512>", 0, 512, 1); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "noise"); + List parameters = new ArrayList(); + parameters.add(ampl); + parameters.add(seed.doubleValue()); + + source(s, parameters); + return s; + } + + private static void sine(double data[], double offs, double ampl, double freq, double phi0, int sampler) { + for (int i = 0; i < data.length; i++) { + data[i] = offs + ampl * Math.sin(2 * Math.PI * freq * i / sampler + phi0); + } + } + + public void sine(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double freq = parameters.get(2); + double phi0 = parameters.get(3); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + sine(data, offs, ampl, freq, phi0, sampler); + } + + public Signal FsineCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double freq = cp.getDouble(arguments, "Frequency", 1.0, Integer.MAX_VALUE, DEF_FREQ); + double phi0 = cp.getDouble(arguments, "Phase (rad)", 0.0, 2.0 * Math.PI, 0.0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "sine"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(freq); + parameters.add(phi0); + + source(s, parameters); + + return s; + } + + private static void sinec(double data[], double offs, double ampl, double freq, int sampler) { + int number = data.length; + for (int i = 0; i < data.length; i++) { + double t = (double) (i - number / 2.0) / (double) sampler; + double arg = 2.0 * Math.PI * freq * t; + if (t != 0.0) + data[i] = (double) (offs + ampl * Math.sin(arg) / arg); + else + data[i] = (double) (offs + ampl * Math.cos(arg)); + } + } + + public void sinec(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double freq = parameters.get(2); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + sinec(data, offs, ampl, freq, sampler); + } + + /** + * FsinecCi generates a (sine(t)) / t. + * + * @param arguments + * @return + */ + + public Signal FsinecCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double freq = cp.getDouble(arguments, "Frequency", 1.0, Integer.MAX_VALUE, DEF_FREQ); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "sinec"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(freq); + + source(s, parameters); + + return s; + } + + private static void cosine(double data[], double offs, double ampl, double freq, double phi0, int sampler) { + for (int i = 0; i < data.length; i++) { + data[i] = offs + ampl * Math.cos(2 * Math.PI * freq * i / sampler + phi0); + } + } + + public void cosine(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double freq = parameters.get(2); + double phi0 = parameters.get(3); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + cosine(data, offs, ampl, freq, phi0, sampler); + } + + public Signal FcosineCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double freq = cp.getDouble(arguments, "Frequency", 1.0, Integer.MAX_VALUE, DEF_FREQ); + double phi0 = cp.getDouble(arguments, "Phase (rad)", 0.0, 2.0 * Math.PI, 0.0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "cosine"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(freq); + parameters.add(phi0); + + source(s, parameters); + + return s; + } + + private static void triangle(double data[], double offs, double ampl, int sampler, double T, double rc, double t0) { + double n = 0; + for (int i = 0; i < data.length; i++) { + double t = (double) (i) / (double) (sampler); + if ((t - T * n + t0) < (T / 2.0)) { + data[i] = (double) (rc * (t - n * T + t0) - ampl + offs); + } + if ((t - T * n + t0) >= (T / 2.0)) { + data[i] = (double) (-rc * (t - n * T + t0) + 3.0 * ampl + offs); + } + if ((t + t0) >= ((n + 1.0) * T)) + n = n + 1.0; + } + } + + public void triangle(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double freq = parameters.get(2); + double phi0 = parameters.get(3); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + double T = (double) (1) / (double) (freq); /* period time */ + double rc = 4.0 * ampl * freq; /* slope */ + double t0 = (phi0 * T) / (double) (2.0 * Math.PI); + triangle(data, offs, ampl, sampler, T, rc, t0); + } + + public Signal FtriangleCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double freq = cp.getDouble(arguments, "Frequency", 1.0, Integer.MAX_VALUE, DEF_FREQ); + double phi0 = cp.getDouble(arguments, "Phase (rad)", 0.0, 2.0 * Math.PI, 0.0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "triangle"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(freq); + parameters.add(phi0); + + source(s, parameters); + + return s; + } + + private static void exp(double data[], double ampl, double T, int sampler) { + double t; + T = T / 1000.0; // T in seconds + for (int i = 0; i < data.length; i++) { + t = (double) i / (double) sampler; + data[i] = ampl * (Math.exp(-t / T)); + } + } + + public void exp(Signal s, List parameters) { + double ampl = parameters.get(0); + double T = parameters.get(1); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + exp(data, ampl, T, sampler); + } + + /******************************************************************** + * FexpCi generates a A*(1-e^(-t/T)). + */ + public Signal FexpCi(Signal s, List arguments) { + + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double T = cp.getDouble(arguments, "t 63.2% (millisec)", 0.000001, 1000000.0, 10.0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "exp"); + List parameters = new ArrayList(); + parameters.add(ampl); + parameters.add(T); + + source(s, parameters); + + return s; + } + + private static void square(double data[], double offs, double ampl, double dutyCycle, int sampler, double T) { + int n = 0; + double B, t; + double dc = dutyCycle / 100.0; + for (int i = 0; i < data.length; i++) { + t = (double) i / (double) sampler; + if ((t - T * n) < (dc * T)) { + B = 1; + } else { + B = -1; + } + data[i] = (double) (offs + ampl * B); + if (t >= ((n + 1) * T)) + n++; + } + } + + public void square(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + double freq = parameters.get(2); + double dutyCycle = parameters.get(3); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + double T = (double) (1) / (double) (freq); /* period time */ + square(data, offs, ampl, dutyCycle, sampler, T); + } + + public Signal FsquarewaveCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + double freq = cp.getDouble(arguments, "Frequency", 1.0, Integer.MAX_VALUE, DEF_FREQ); + double dutyCycle = cp.getDouble(arguments, "Duty-cycle <0% .. 100%>", 0.0, 100.0, 50.0); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "square"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + parameters.add(freq); + parameters.add(dutyCycle); + + source(s, parameters); + + return s; + } + private static void ramp(double data[], double offs, double ampl, int sampler) { + double rc = ampl*(double)sampler/(double)(data.length -1); + double t; + for (int i = 0; i < data.length; i++) { + t = (double) i / (double) sampler; + data[i] = (double) (rc*t + offs); + } + } + + public void ramp(Signal s, List parameters) { + double offs = parameters.get(0); + double ampl = parameters.get(1); + int sampler = s.getDataSampleRate() * 10; + + double data[]; + if (s.getDataType() == Signal.IMAG) + data = s.getImagData(); + else + data = s.getRealData(); + + ramp(data, offs, ampl, sampler); + } + + public Signal FrampCi(Signal s, List arguments) { + + double offs = cp.getDouble(arguments, "Offset", Integer.MIN_VALUE, Integer.MAX_VALUE, 0.0); + double ampl = cp.getDouble(arguments, "Amplitude", 0.0, Integer.MAX_VALUE, DEF_AMPL); + short dtype = (short) cp.getInt(arguments, "Type <0=Real,1=Imag,2=Complex>", Signal.REAL, Signal.COMP, + Signal.REAL); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + + setSignalValues(s, number, sample, dtype, "ramp"); + List parameters = new ArrayList(); + parameters.add(offs); + parameters.add(ampl); + + source(s, parameters); + + return s; + } + + public Signal SourcesCi(List arguments, String command) { + String signalname = cp.getString(arguments, "Signal", command.substring(1)); + Signal outputSignal = null; + + Signal s = signals.get(signalname); /* Find the correct signal */ + + if (s == null) /* Signal did not exist yet */ + { + s = new Signal(signalname); + signals.put(signalname, s); + } + + Method method = null; + String methodName = functions.get(command)[0]; + try { + method = this.getClass().getMethod(methodName, Signal.class, List.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + outputSignal = (Signal) method.invoke(this, s, arguments); + } catch (IllegalAccessException | IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + return outputSignal; + } +} \ No newline at end of file diff --git a/asm/src/signals/SourcesBase.java b/asm/src/signals/SourcesBase.java new file mode 100644 index 0000000..8c538cb --- /dev/null +++ b/asm/src/signals/SourcesBase.java @@ -0,0 +1,36 @@ +package signals; + +import java.util.Map; + +import console.CommandLineParser; + +public class SourcesBase { + protected final Map signals; + protected CommandLineParser cp; + public static final int DEF_N = 9; /* 2^9 = 512 = default number of samples */ + + public SourcesBase(Map signals, CommandLineParser cp) { + this.signals = signals; + this.cp = cp; + } + + protected void setSignalValues(Signal s, int length, int sampleRate, short dataType, + String description) { + s.setDate(); + s.setPixelFormat(Signal.DATA_PIXEL_FORMAT); + s.setDataLength(length); + s.setDataRecords(1); + s.setDataFileSeq(Signal.DATA_FILE_SEQ); + s.setDataBitsPerSample(Signal.BPS_SAMPLE); + s.setDataChannels(1); + s.setDataSampleRate(sampleRate); + s.setDataDomain(Signal.TIME); + s.setDataType(dataType); + s.setDataIdString(Signal.ASM_ID_STRING); + s.setDataUserText("DataUserText"); + s.setDataDescription(description); + s.setHScale(1.0); + s.setRecord(0); + s.setChannel(0); + } +} diff --git a/asm/src/signals/Windowing.java b/asm/src/signals/Windowing.java new file mode 100644 index 0000000..4d53035 --- /dev/null +++ b/asm/src/signals/Windowing.java @@ -0,0 +1,240 @@ +package signals; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import console.CommandLineParser; + +public class Windowing extends SourcesBase { + + public static final Map windows = new HashMap() { + { + put("wblackman", new String[] {"",""}); + put("wblock", new String[] {"",""}); + put("wgauss", new String[] {"",""}); + put("whanning", new String[] {"",""}); + put("whamming", new String[] {"",""}); + put("wkaiser", new String[] {"",""}); + put("wtriangle", new String[] {"",""}); + } + }; + + public Windowing(Map signals, CommandLineParser cp) { + super(signals, cp); + } + + public static void windowing(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length, + int windowing) { + switch (windowing) { + case 0: + wblock(re, im, re_out, im_out, offset, length); + break; + case 1: + whanning(re, im, re_out, im_out, offset, length); + break; + case 2: + whamming(re, im, re_out, im_out, offset, length); + break; + case 3: + wgauss(re, im, re_out, im_out, offset, length); + break; + case 4: + wblackman(re, im, re_out, im_out, offset, length); + break; + case 5: + wkaiser(re, im, re_out, im_out, offset, length); + break; + case 6: + wtriangle(re, im, re_out, im_out, offset, length); + break; + } + } + + public static void wblackman(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double blackman = (0.42 - 0.50 * Math.cos((2 * Math.PI * i) / (length - 1.0)) + + 0.08 * Math.cos((4.0 * Math.PI * i) / (length - 1))); + int index = i + offset; + re_out[index] = re[index] * blackman; + im_out[index] = im[index] * blackman; + } + } + + public void wblackman(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + wblackman(data_real, data_imag, data_real, data_imag, 0, length); + } + + public static void wblock(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = offset; i < length + offset; i++) { + re_out[i] = re[i]; + im_out[i] = im[i]; + } + } + + public void wblock(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + } + + public static void wgauss(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double gaus = Math.exp(-0.5 * Math.pow((3.0 * (i - (length - 1.0) / 2.0) * 2.0 / (length - 1.0)), 2.0)); + int index = i + offset; + re_out[index] = re[index] * gaus; + im_out[index] = im[index] * gaus; + } + } + + public void wgauss(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + wgauss(data_real, data_imag, data_real, data_imag, 0, length); + } + + public static void whanning(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double hanning = (1.0 - Math.cos((2.0 * Math.PI * i) / (length - 1.0))) / 2.0; + int index = i + offset; + re_out[index] = re[index] * hanning; + im_out[index] = im[index] * hanning; + } + } + + public void whanning(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + whanning(data_real, data_imag, data_real, data_imag, 0, length); + } + + public static void whamming(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double hamming = 0.538 - 0.462 * Math.cos(2.0 * Math.PI * i / (length - 1.0)); + int index = i + offset; + re_out[index] = re[index] * hamming; + im_out[index] = im[index] * hamming; + } + } + + public void whamming(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + whamming(data_real, data_imag, data_real, data_imag, 0, length); + } + + public static void wkaiser(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double kaiser = (1 - 1.24 * Math.cos(2 * Math.PI * i / (length - 1)) + + 0.244 * Math.cos(4 * Math.PI * i / (length - 1)) + - 0.00305 * Math.cos(6 * Math.PI * i / (length - 1))) / 2.48; + int index = i + offset; + re_out[index] = re[index] * kaiser; + im_out[index] = im[index] * kaiser; + } + } + + public void wkaiser(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + wkaiser(data_real, data_imag, data_real, data_imag, 0, length); + } + + public static void wtriangle(double[] re, double[] im, double[] re_out, double[] im_out, int offset, int length) { + for (int i = 0; i < length; i++) { + double triangle = 1 - Math.abs(i - ((length - 1) / 2.0)) / ((length - 1) / 2.0); + int index = i + offset; + re_out[index] = re[index] * triangle; + im_out[index] = im[index] * triangle; + } + } + + public void wtriangle(Signal s) { + double[] data_real = s.getRealData(); + double[] data_imag = s.getImagData(); + int length = s.getDataLength(); + + for (int i = 0; i < length; i++) { + data_real[i] = data_imag[i] = 1.0; + } + wtriangle(data_real, data_imag, data_real, data_imag, 0, length); + } + + public Signal WindowCi(List arguments, String window) { + + String signalname = cp.getString(arguments, "Signal", window.substring(1)); + int n = cp.getInt(arguments, "Number of elements (2^n)", Signal.MIN_N, Signal.MAX_N, DEF_N); + int sample = cp.getInt(arguments, "Samplerate in 10Hz", 1, Short.MAX_VALUE, Signal.SAMPLE_RATE); + + int number = (int) Math.pow(2, n); + Signal im = signals.get(signalname); /* Find the correct signal */ + + if (im == null) /* Signal did not exist yet */ + { + im = new Signal(signalname); + signals.put(signalname, im); + } + + setSignalValues(im, number, sample, Signal.COMP, window); + im.setMode(Signal.REAL_M); + double[] data_real = new double[number]; + double[] data_imag = new double[number]; + im.setRealData(data_real); + im.setImagData(data_imag); + + Method method = null; + String methodName = window; + try { + method = this.getClass().getMethod(methodName, Signal.class); + } catch (NoSuchMethodException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (method == null) + return null; + + try { + method.invoke(this, im); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return im; + } +} \ No newline at end of file diff --git a/asm/src/util/Util.java b/asm/src/util/Util.java new file mode 100644 index 0000000..4f07db0 --- /dev/null +++ b/asm/src/util/Util.java @@ -0,0 +1,27 @@ +package util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; + +public class Util { + + public Util() { + // TODO Auto-generated constructor stub + } + public static void dumpArray(double [] re, double [] im, String fileName) { + try { + PrintWriter writer = new PrintWriter(new File(fileName)); + int offset = 0; + for (int i = 0; i < re.length; i++) { + writer.format(String.format("%6d) Re: %g Im: %g\n", i, re[i + offset], im[i + offset])); + } + writer.flush(); + writer.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/doc/asm.tex b/doc/asm.tex new file mode 100644 index 0000000..a91adba --- /dev/null +++ b/doc/asm.tex @@ -0,0 +1,1328 @@ +\documentclass{report} +\usepackage{graphicx} +\newcommand{\bs}{$\backslash$} + + % The preamble begins here. +\title{Another Signal Manager} +\author{Erwin Waterlander} +\date{Oct 21 2022} % Deleting this command produces today's date. + +\newcommand{\bc}{\scriptsize} +\newcommand{\ec}{\normalsize} + +\begin{document} % End of preamble and beginning of text. + +\maketitle % Produces the title. + +\tableofcontents + +\chapter{Introduction}\label{chap:intro} + +This document can be downloaded from this URL:\\ +\texttt{https://waterlan.home.xs4all.nl/asm.html} + + +\section{What is ASM?} + + +ASM is a program for digital signal processing for educational +purposes. + +This is a port of the original version made in 1993 by Edwin Zoer and me on an +Acorn Archimedes computer running RISC-OS. + +\section{History} + +\subsection{AIM : Another Image Manager} + +also known as: +Atari Image Manager, +Archimedes Image Manager, +Amiga Image Manager. + +\paragraph{} +The image processing program AIM was originally developed for the +ATARI-ST by Frans Groen and Robert de Vries. Since the first +version of AIM, the improvement of this public domain image +processing package has become a joint effort of a number of +people from the Delft University of Technology and the University +of Amsterdam. +AIM has been ported to the ARCHIMEDES (Arthur version) by Robert +Ellens, Damir Sudar and Alle-Jan van der Veen. +Ed Doppenberg was successful in the port to RISC-OS. +AIM has been written in the C-language. +AIM is limited in functionality as well as in flexibility. +The main purpose of the program is to experiment with digital +image processing. + +The latest version 3.15 (1995) for Archimedes RISC-OS can be downloaded +from http://wuerthner.dyndns.org/others.html + +On the Polytechnic of Enschede the Archimedes RISC-OS version of AIM was used +in practical lessons in image processing. Polytechnic of Enschede (Hogeschool +Enschede), the Netherlands, is called Saxion hogescholen (www.saxion.nl) +today. + + +\subsection{ASM : Another Signal Manager} + +In 1993 the idea came to make a program like AIM, but then for signal +processing: ASM for RISC-OS. The task of our final examination for the +Polytechnic of Enschede was to create ASM for RISC-OS. + +We made ASM at and with support of the Technical University of Delft, faculty +Applied Physics, Pattern Recognition group (Tom Hoeksma), and with support from +the Technisch Physische Dienst, Delft (Ed Doppenberg). Our starting point was +a stripped down version of AIM made by Ed Doppenberg. It was only one window +with a command line interpreter. + +In 1993 Edwin and I had only basic knowledge of ANSI C and no knowledge about +making user interfaces for RISC-OS. Our goal was to put as much as possible +functionality in the program in only three months. + +With the first RISC-OS version we created it was possible to generate signals +and do some basic processing on them. The program was made for use during +practical lessons in digital signal processing at the polytechnic in Enschede. + +The original intention was that other students would develop ASM further. But +it was Ed Doppenberg who did a thorough revision of the source code and added +some professional functionality. That version of ASM (for RISC-OS) is not free +available for the public domain. + +In 1997 I ported the first version of ASM for RISC-OS to DOS using DJGPP 2.01 +(gcc 2.7.2). See djgpp.txt. I used the Allegro 2.2 graphics library. +Allegro is a library intended for use in computer games. It was initially +conceived on the Atari ST. See allegro.txt. + +In 1997 my primary goal was to port the program to a working version on DOS, for +the fun of programming and because I had no Archimedes computer. That means I +only changed the graphical interface. I tried to keep the source code as much +as possible the same. There are large changes in file plotutil.c. Files aim.c +and command.c have been replaced by asm.c. + +Allegro development went on, supporting more platforms. In 2007 I build ASM +also for Windows and Linux. I replaced some deprecated Allegro api calls with +new ones, and build ASM for DOS, Windows and Linux. A few minor problems have +been fixed. For the rest it's the same version as in 1997. + +For many years I had in the back of my mind the idea to make a windowed +version, like the original version on RiscOS. In 2021 I started porting ASM to +Java. In Oct 2022 the first alpha version was ready. + + +\paragraph{} +This version of ASM is Public Domain software.\\\\ +Erwin Waterlander\\ +e-mail: waterlan@xs4all.nl + + +\chapter{User interface} + +\section{Graphical interface} + +The main window is a console in which the user can type the +commands. Each signal is displayed in a separate window. + +\section{Command line interface} + +ASM has the same command line interface as AIM. + +\paragraph{} +Commands can be abbreviated as long as they stay unique. + +\paragraph{} +Parameters are separated by spaces. +If you don't give all the parameters that are possible on +a certain command ASM will take default values. + + +\chapter{Functionality} + +\section{Data-format conversion} + +All data is in 64 bit floating point (type double). + +\section{Domain conversion} + +Conversions can be done between the different domains: + +\begin{table}[h] +\begin{center} +\begin{tabular}{|l|c|c|c|c|c|} +\hline +From \bs To & Time & Frequency & Amplitude & Magnitude & Phase \\ +\hline +Time & & X & X & X & X \\ +\hline +Frequency & X & & & X & X \\ +\hline +Amplitude & & & & & \\ +\hline +Magnitude & & & & & \\ +\hline +Phase & & & & & \\ +\hline +\end{tabular} +\label{tab:conversions} +\caption{Domain conversions} +\end{center} +\end{table} + +\subsection{From time to frequency} + +\paragraph{fft}: Fast-Fourier- Transformation + +\bc +\begin{verbatim} +command: fft input-signal, output-signal, length, window-type, average-type +default : a , b , 9 , 1 , 0 +range : , , <7-12>, <0-6> , <0-1> +domain : time +\end{verbatim} +\ec + +\begin{verbatim} +Windows: +0 block +1 Hanning +2 Hamming +3 Gauss +4 Blackman +5 Kaiser +6 triangle +\end{verbatim} + +average-type, see section \ref{sec:freqtomag} and \ref{sec:freqtophas}. + +FFT is done per record. The default length is the record length of the input signal. + +\subsection{From frequency to time} + +\paragraph{ifft}: Inverse Fast-Fourier-Transformation + +\bc +\begin{verbatim} +command: ifft input-signal, output-signal +default : a , b +range : , +domain : frequency +\end{verbatim} +\ec + +\subsection{From time to amplitude} + +\paragraph{histogram} + +\bc +\begin{verbatim} +command: histogram input-signal, output-signal, buckets +default : a , b , 9 +range : , , <7-12> +domain : time +\end{verbatim} +\ec + +The number of buckets is given as a power of 2. So 9 means $2^9=512$ buckets. + +\subsection{From frequency to magnitude}\label{sec:freqtomag} + +There are two different ways of averaging:\\ + +Average-type 0: + +\begin{enumerate} +\item Calculate magnitude for every record:\\ + \( |F(u)| = \sqrt{ Re^{2}(u) + Im^{2}(u) } , u = 0,1,...,N-1 \) +\item sum all the results from the different records +\item and calculate \( 10\cdot\log \). +\end{enumerate} + +Average-type 1: + +\begin{enumerate} +\item Sum all the different records, +\item calculate the magnitude of the result\\ + \( |F( u)| = \sqrt{ Re^{2}( u) + Im^{2}( u) } , u = 0,1,...,N-1 \) +\item and calculate \( 10\cdot\log \). +\end{enumerate} +\paragraph{magnitude}: Calculate the signal's magnitude + +\bc +\begin{verbatim} +command: : magnitude input-signal, output-signal, channel-no, average-type, log +default : a , input-signal, 0 , 0 , 0 +range : , , <0-max> , <0-1> , <0-1> +domain : frequency + +log: +0 = linear Y-axis +1 = log Y- axis +\end{verbatim} +\ec + +\subsection{From frequency to phase}\label{sec:freqtophas} + +Average-type 0: + +\begin{enumerate} +\item Calculate the phase of every record:\\ + \( \Phi(u) = tan^{-1}\left[ \frac{Im(u)}{Re(u)}\right], u = 0, 1, ..., N-1\) +\item Sum the different records and divide by the number of records. +\end{enumerate} + +Average-type 1: + +\begin{enumerate} +\item Sum the different records and divide by the number of records. +\item Calculate the phase of the result:\\ + \( \Phi(u) = tan^{-1}\left[ \frac{Im(u)}{Re(u)}\right], u = 0, 1, ..., N-1 \) +\end{enumerate} +\ec +\paragraph{phase}: Calculate the signal's phase + +\bc +\begin{verbatim} +command: : phase input-signal, output-signal, channel-no, average-type +default : a , input-signal, 0 , 0 +range : , , <0-max> , <0-1> +domain : frequency +\end{verbatim} +\ec + +\subsection{From time to magnitude} + +Not implemented. + +\subsection{From time to phase} + +Not implemented. + +\section{Mathematical functions} + +There are a few simple mathematical functions in ASM. The functions +can be performed on signals in any domain. For functions that work +on more than one input-signal the record-length and the number of +channels have to be the same for all the input signals. All +constant values are values between $ ~ = INT\_MIN = -2147483647 $ +and $ ~ = INT\_MAX = 2147483647 $. + +\paragraph{clear}: Make all elements 0 + +\[ Re(out) = 0 \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : clear Input-signal +default : a +range : +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{assign}: Assign a constant value to all elements + +\[ Re(out) = C \] +\[ Im(out) = C \] + +\bc +\begin{verbatim} +command: : assign Input-signal, real-part, imag-part +default : a , 1 , 1 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + + +\paragraph{inv}: Invert all elements + +\[ Re(out) = -1*Re(in) \] +\[ Im(out) = -1*Im(in) \] + +\bc +\begin{verbatim} +command: : inv Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{conjugate}: + +\[ Re(out) = Re(in) \] +\[ Im(out) = -1*Im(in) \] + +\bc +\begin{verbatim} +command: : conjugate Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{cabs}: Calculate absolute value of each element + +\[ Re(output) = \sqrt{Re^{2}(input) + Im^{2}(input)} \] +\[ Im(output) = 0 \] + +\bc +\begin{verbatim} +command: : cabs Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{cadd}: Add a constant value + +\[ Re(out) = Re(in) + C \] +\[ Im(out) = Im(in) \] + +\bc +\begin{verbatim} +command: : cadd Input-signal, constant, Output-signal +default : a , 0 , input-signal +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + + +\paragraph{cmultiply}: Multiply by a constant value + +\[ Re(out) = C*Re(in) \] +\[ Im(out) = C*Im(in) \] + +\bc +\begin{verbatim} +command: : cmultiply Input-signal, constant, Output-signal +default : a , 1 , input-signal +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{cdivide}: Divide by a constant + +\[ Re(out) = \frac{Re(in)}{C} \] +\[ Im(out) = \frac{Im(in)}{C} \] + +\bc +\begin{verbatim} +command: : cdivide Input-signal, constant, Output-signal +default : a , 1 , input-signal +range : , <1-max> , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + + +\paragraph{abs}: Absolute difference between two signals + +\[ Re(out) = \sqrt{ (Re(in1) - Re(in2))^{2} + (Im(in1) - Im(in2))^{2} } \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : abs Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{add}: Add two signals + +\[ Re(out) = Re(in1) + Re(in2) \] +\[ Im(out) = Im(in1) + Im(in2) \] + +\bc +\begin{verbatim} +command: : add Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{substract}: Substract two signals + +\[ Re(out) = Re(in1) - Re(in2) \] +\[ Im(out) = Im(in1) - Im(in2) \] + +\bc +\begin{verbatim} +command: : substract Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{multiply}: Multiply two signals + +\[ Re(out) = \frac{ Re(in1) * Re(in2) - Im(in1) * Im(in2) }{C} \] +\[ Im(out) = \frac{ Re(in1) * Im(in2) + Im(in1) * Re(in2) }{C} \] + +\bc +\begin{verbatim} +command: : multiply Input-signal1, Input-signal2, constant, Output-signal +default : a , b , 1 , input-signal2 +range : , , <1-max>, +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{divide}: Divide two signals + +\[ Re(out) = \frac{\sqrt{ Re^{2}(in1) + Im^{2}(in1)} }{ 1 + \sqrt{Re^{2}(in2) + Im^{2}(in2)}} \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : divide Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{sine}: Calculate sine + +\[ Re(out) = \sin (Re(in)) \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : sine Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{cosine}: Calculate sine + +\[ Re(out) = \cos (Re(in)) \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : cosine Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{ln}: logarithm + +\[ Re(out) = \ln{Re(in)} \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : ln Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{log}: $ ^{10}\log $ + +\[ Re(out) = \log{Re(in)} \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : log Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{epow}: + +\[ Re(out) = e^{Re(in)} \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : epow Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{tenpow}: + +\[ Re(out) = 10^{Re(in)} \] +\[ Im(out) = 0 \] + +\bc +\begin{verbatim} +command: : tenpow Input-signal, Output-signal +default : a , input-signal +range : , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + + +\paragraph{minimum}: minimum of two signals + +\[ Re(out) = \sqrt{Re^{2}(in1) + Im^{2}(in1)} < \sqrt{Re^{2}(in2) + Im^{2}(in2)} ? Re(in1) : Re(in2) \] +\[ Im(out) = \sqrt{Re^{2}(in1) + Im^{2}(in1)} < \sqrt{Re^{2}(in2) + Im^{2}(in2)} ? Im(in1) : Im(in2) \] + +\bc +\begin{verbatim} +command: : minimum Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\paragraph{maximum}: maximum of two signals + +\[ Re(out) = \sqrt{Re^{2}(in1) + Im^{2}(in1)} > \sqrt{Re^{2}(in2) + Im^{2}(in2)} ? Re(in1) : Re(in2) \] +\[ Im(out) = \sqrt{Re^{2}(in1) + Im^{2}(in1)} > \sqrt{Re^{2}(in2) + Im^{2}(in2)} ? Im(in1) : Im(in2) \] + +\bc +\begin{verbatim} +command: : maximum Input-signal1, Input-signal2, Output-signal +default : a , b , input-signal2 +range : , , +domain : time, frequency, amplitude, magnitude, phase +\end{verbatim} +\ec + +\section{Cross-correlation} + +The cross-correlation of two signals of N samples is calculated as follows: + +\begin{enumerate} + \item Zeropad the signals per record, to prevent wrap-around pollution. + \item Multiply the signals with an N points window. + \item Calculate the 2N points FFT of the signals. + \item Multiply the complex conjugate of the first with the second signal. + \item Calculate the 2N points IFFT. +\end{enumerate} + +\paragraph{correlation}: calculate cross-correlation of two signals + +\bc +\begin{verbatim} +command: : correlation Input-signal1, Input-signal2, Output-signal, window-type +default : a , b , input-signal2, 0 +range : , , , <0-6> +domain : time +\end{verbatim} +\ec + +\begin{verbatim} +Windows: +0 block +1 Hanning +2 Hamming +3 Gauss +4 Blackman +5 Kaiser +6 triangle +\end{verbatim} + +\section{Convolution} + +The convolution of two signals of N samples is calculated as follows: + +\begin{enumerate} + \item Zeropad the signals per record, to prevent wrap-around pollution. + \item Multiply the signals with an N points window. + \item Calculate the 2N points FFT of the signals. + \item Multiply the first with the second signal. + \item Calculate the 2N points IFFT. +\end{enumerate} + + +\paragraph{convolution}: calculate convolution of two signals + +\bc +\begin{verbatim} +command: : convolution Input-signal1, Input-signal2, Output-signal, window-type +default : a , b , input-signal2, 0 +range : , , , <0-6> +domain : time +\end{verbatim} +\ec + +\section{Functions} + +ASM can generate some standard signals. +Currently the functions are limited to 1 record and 1 channel. + +\begin{itemize} +\item ts = sample time +\item A = Amplitude +\item Amax = 2147483647 +\item B = offset +\item Bmin = -2147483647 +\item Bmax = 2147483647 +\item T = period time +\item f = frequency +\item fmax = 2147483647 +\item data-type: 0=real, 1=imaginary, 2=complex +\item N = number of elements = $2^{n}$ +Nmin = 128 (n=7), Nmax = 4096 +\item Smax = 65535, maximal sample-rate (in 10 Hz) +\end{itemize} + +Sample-rate is always given in 10 (Hz). + +\paragraph{fdelta}: + +\[ x(n \cdot t_{s}) = A,~ n \cdot t_{s} = t_{d},~ n=0,1,...,N-1 \] +\[ x(n \cdot t_{s}) = 0,~ n \cdot t_{s} \neq t_{d},~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : fdelta signal, A , td (ms) , data-type, n , sample-rate +default : a , 255 , 0 , 0 , 9 , 1024 +range : , <0-Amax> , <0-t(N-1)> , <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fconstant}: + +\[ x(n \cdot t_{s}) = A,~ n=0,1,...,N-1 \] +\bc +\begin{verbatim} +command: : fconstant signal, A , data-type, n , sample-rate +default : a , 255 , 0 , 9 , 1024 +range : , <0-Amax> , <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fstep}: + +\[ x(n \cdot t_{s}) = B,~ n \cdot t_{s} < t_{step},~ n=0,1,...,N-1 \] +\[ x(n \cdot t_{s}) = A+B,~ n \cdot t_{s} \geq t_{step},~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : fstep signal, B , A , tdelay(ms) , data-type, n , sample-rate +default : a , 0 , 255 , 0 , 0 , 9 , 1024 +range : , , <0-Amax> , <0-t(N-1)> , <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fsquare}: + +\[ x(n \cdot t_{s}) = A+B,~ 0 \leq n \cdot t_{s} < dc \cdot T,~ n=0,1,...,N-1 \] +\[ x(n \cdot t_{s}) = -A+B,~ dc \cdot T \leq n \cdot t_{s} < T,~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : fsquare signal, B , A , f , dc , data-type, n , sample-rate +default : a , 0 , 255 , 100 , 50 , 0 , 9 , 1024 +range : , , <0-Amax> , <1-fmax> , <0-100>, <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +dc = duty cycle + +\paragraph{framp}: + +\[ x(n \cdot t_{s}) = \frac{A}{t_{s} \cdot (N-1)} \cdot n \cdot t_{s} + B,~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : framp signal, B , A ,data-type, n , sample-rate +default : a , 0 , 255 , 0 , 9 , 1024 +range : , , <0-Amax> , <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{ftriangle}: + +\[ x(n \cdot t_{s}) = \frac{4A}{T}\cdot(n \cdot t_{s} + \frac{\phi_{0} \cdot T}{2\pi})-A+B,~ 0 \leq n \cdot t_{s} < \frac{1}{2}T,~ n=0,1,...,N-1 \] +\[ x(n \cdot t_{s}) = \frac{-4A}{T}\cdot(n \cdot t_{s} + \frac{\phi_{0} \cdot T}{2\pi})+3A+B,~ \frac{1}{2}T \leq n \cdot t_{s} < T,~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : ftriangle signal, B , A , f , phi0 , data-type, n , sample-rate +default : a , 0 , 255 , 100 , 0 , 0 , 9 , 1024 +range : , , <0-Amax> , <1-fmax> , <0-2pi>, <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fsine}: + +\[ x(n \cdot t_{s}) = A \sin(2\pi fnt_{s} + \phi_{0}) + B,~ n=0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : fsine signal, B , A , f , phi0 , data-type, n , sample-rate +default : a , 0 , 255 , 100 , 0 , 0 , 9 , 1024 +range : , , <0-Amax> , <1-fmax> , <0-2pi>, <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fsinc}: + +\[ x(n \cdot t_{s}) = A \left( \frac{\sin (2\pi fnt_{s})}{2\pi fnt_{s}} \right) + B,~ n=1,...,N-1 \] +\[ x(n \cdot t_{s}) = A \cos (2\pi fnt_{s})+B,~ n=0 \] + +\bc +\begin{verbatim} +command: : fsinc signal, B , A , f , data-type, n , sample-rate +default : a , 0 , 255 , 100 , 0 , 9 , 1024 +range : , , <0-Amax> , <1-fmax> , <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fcosine}: + +\[ x(n \cdot t_{s}) = A \cos (2\pi fnt_{s} + \phi_{0})+B,~ n=0,...,N-1 \] + +\bc +\begin{verbatim} +command: : fcosine signal, B , A , f , phi0 , data-type, n , sample-rate +default : a , 0 , 255 , 100 , 0 , 0 , 9 , 1024 +range : , , <0-Amax> , <1-fmax> , <0-2pi>, <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fexp}: + +\[ x(n \cdot t_{s}) = A ( 1 - e^{\frac{-n\cdot t_{s}}{t_{63.2\%}}}),~ n=0,...,N-1 \] + +\bc +\begin{verbatim} +command: : fexp signal, A , t63.2(ms), data-type, n , sample-rate +default : a , 255 , 0.10 , 0 , 9 , 1024 +range : , <0-Amax> ,<1e-6-1e6>, <0-2> , <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\paragraph{fnoise}: pseudo random noise. + +\bc +\begin{verbatim} +command: : fnoise signal, A , data-type, seed , n , sample-rate +default : a , 255 , 0 , 1 , 9 , 1024 +range : , <0-Amax> , <0-2> , <0-512>, <7-12>, <1-Smax> +domain : time +\end{verbatim} +\ec + +\section{Conditioning} + +Zero padding is extending each record of N samples with N zeros. +The output signal has a record length of 2N. + +\paragraph{zeropadding}: + +\bc +\begin{verbatim} +command: : zeropad input-signal, output-signal +default : a , input-signal +range : , +domain : time +\end{verbatim} +\ec + +\section{Windowing} + +\paragraph{wblock}: block window + +\[ W(n) = 1,~ n = 0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : wblock signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{whanning}: Hanning window + +\[ W(n) = \frac{1}{2}\left( 1- \cos (\frac{2\pi n}{N-1}) \right) ,~ n = 0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : whanning signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{whamming}: Hamming window + +\[W(n) = 0.538 - 0.462 \cos (\frac{2\pi n}{N-1}) ,~ n = 0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : whamming signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{wgauss}: Gauss window +\large +\[W(n) = e^{- \frac{1}{2} \left( \frac{\alpha \cdot (n - \frac{N-1}{2}) \cdot 2 }{\frac{N-1}{2}} \right)^{2}},~ n = 0,1,...,N-1 \] +\normalsize +\[ \alpha = 3.0 \] + +\bc +\begin{verbatim} +command: : wgauss signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{wblackman}: Blackman window + +\[ W(n) = 0.42 - 0.5\cos (\frac{2\pi n}{N-1}) + 0.08\cos (\frac{4\pi n}{N-1}),~ n = 0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : wblackman signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{wkaiser}: Kaiser window + +\[ W(n) = \frac{1}{2.48} \left( 1- 1.24\cos (\frac{2\pi n}{N-1}) + 0.244\cos (\frac{4\pi n}{N-1}) - 0.00305\cos (\frac{6\pi n}{N-1}) \right),\] +\[ n = 0,1,...,N-1 \] + + +\bc +\begin{verbatim} +command: : wkaiser signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\paragraph{wtriangle}: + +\[ W(n) = 1 - \left| \frac{n-\frac{N-1}{2}}{\frac{N-1}{2}} \right| ,~ n = 0,1,...,N-1 \] + +\bc +\begin{verbatim} +command: : wtriangle signal, n , samplerate +default : a , 9 , 1024 +range : , <7-12> , (1-Smax) +domain : time +\end{verbatim} +\ec + +\section{Presentation functions} + +\subsection{Time domain}\label{sec:timedom} + +\paragraph{real}: Show the real part of the signal. + +\bc +\begin{verbatim} +command: : real signal, channel-no , record-no +default : a , 0 , 0 +range : , <0-max> , <0-max> +domain : time, frequency +\end{verbatim} +\ec + + +\paragraph{imaginary}: Show the imaginary part of the signal. + +\bc +\begin{verbatim} +command: : imaginary signal, channel-no , record-no +default : a , 0 , 0 +range : , <0-max> , <0-max> +domain : time, frequency +\end{verbatim} +\ec + +\subsection{Frequency domain} + +\paragraph{real}: See section \ref{sec:timedom} + +\paragraph{imaginary}: See section \ref{sec:timedom} + +\paragraph{bode}: Show bode diagram + +\bc +\begin{verbatim} +command: : bode signal, channel-no , record-no +default : a , 0 , 0 +range : , <0-max> , <0-max> +domain : frequency +\end{verbatim} +\ec + +\subsection{Magnitude and phase domain} + +\subsection{Generic functions} + +\paragraph{doff}: display off, do not display signals + +\bc +\begin{verbatim} +command: : doff +\end{verbatim} +\ec + +\paragraph{don}: display on, display signals + +\bc +\begin{verbatim} +command: : don +\end{verbatim} +\ec + +\paragraph{boff}: bar display off, display signals as normal graphs. + +\bc +\begin{verbatim} +command: : boff +\end{verbatim} +\ec + +\paragraph{bon}: bar display on, display signals as bargraphs. + +\bc +\begin{verbatim} +command: : bon +\end{verbatim} +\ec + +\paragraph{display}: display a signal, regardless of \textbf{doff/don}. + +\bc +\begin{verbatim} +command: : display signal, channel-no , record-no +default : a , 0 , 0 +range : , <0-max> , <0-max> +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +\paragraph{xscale}: set horizontal scale factor. + +\bc +\begin{verbatim} +command: : xscale signal, scale-factor +default : a , 1 +range : , <0-10> +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +\paragraph{print}: print values of signal in commandline window. + +\bc +\begin{verbatim} +command: : print signal, channel-no , record-no +default : a , 0 , 0 +range : , <0-max> , <0-max> +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +\paragraph{info}: print header information. + +\bc +\begin{verbatim} +command: : info signal +default : a +range : +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +\paragraph{list}: list all signals. + +\bc +\begin{verbatim} +command: : list +\end{verbatim} +\ec + +\section{Other functions} + +\paragraph{writf}: write file. + +\bc +\begin{verbatim} +command: : writef signal, filename , usertext, description, bits-per-sample +default : a , signalname , , , bits-per-sample +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +\paragraph{readf}: read file. + +\bc +\begin{verbatim} +command: : readf filename , signalname +default : a , filename +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + + +\paragraph{shift}: shift a signal. + +\bc +\begin{verbatim} +command: : shift signal , shift , output-signal +default : a , 0 , input-signal +range : ,<-length-length>, +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +Shifting is done per channel. +Maximum shift is one record length. + +\paragraph{rotate}: rotate a signal. + +\bc +\begin{verbatim} +command: : rotate signal , rotate , output-signal +default : a , 0 , input-signal +range : ,<-length-length>, +domain : time, frequency, magnitude, phase, amplitude +\end{verbatim} +\ec + +Rotation is done per channel. +Maximum rotation is one record length. + +\paragraph{clip}: clip a signal. + +\bc +\begin{verbatim} +command: : clip signal , left , right , output-signal +default : a , 0 , length , input-signal +range : , <0-length> , <0-length>, +domain : time +\end{verbatim} +\ec + +\bc +\begin{verbatim} +command: : clip signal , left , right , attenuation ,output-signal +default : a , 0 , length , 50 (dB) , input-signal +range : , <0-1/2Fs> , <0-1/2Fs> , <0-100> , +domain : frequency +\end{verbatim} +\ec + +Clipping is done per record. + +\section{New functions} + +The functions listed in this section are new. They did not exist in +the original RiscOS version of ASM. + +\paragraph{dosshell}: Start a system shell. Signals stay in memory. + +\paragraph{} +This commands starts a system shell. The user can run some text commands in the +shell. When the user exits the shell, he/she comes back in ASM. This command +has only use in the DOS operating system. In multi-tasking operating systems +like Windows and Linux the shell immediately ends and the user goes direct +back to ASM. + +\bc +\begin{verbatim} +command: dosshell +\end{verbatim} +\ec + +\paragraph{bitmap}: Save the signal image in a bitmap file. + +\bc +\begin{verbatim} +command: bitmap signal , filename , +default: a , a , 1 +range: , , <1-3> +\end{verbatim} +\ec + + +format\\ +1 = pcx (Zsoft Paintbrush)\\ +2 = tga (Truevision Targa)\\ +3 = bmp (Windows Bitmap) + +\paragraph{signaldir}: Set the directory path where to store and read signals. + +\bc +\begin{verbatim} +command: signaldir directory-path +\end{verbatim} +\ec + +\paragraph{samplerate}: Set the default samplerate. + +\bc +\begin{verbatim} +command: samplerate samplerate +default: the current samplerate +\end{verbatim} +\ec + +\paragraph{readwav}: Read a wav file. + +\bc +\begin{verbatim} +command: readwav filename signalname +default: a a +\end{verbatim} +\ec + +Read a signal from a RIFF WAV file. Only 8 bit mono +WAV files are supported. +Note that reading large WAV files will cause memory problems. +The data of 8 bit mono WAV files is of type 'unsigned char'. + +\paragraph{} +The function does not check if the number of samples is +a power of 2, nor does it chop the number of samples to a power of 2. +Data is also not split in records. See \ref{sec:header}. +This function needs to be improved. + +\paragraph{macro}: Run a macro. + +\bc +\begin{verbatim} +command: macro macro-filename +\end{verbatim} +\ec + +\chapter{Data format} + +\section{Header}\label{sec:header} + +All signals have information in the form of a header. To show header +information use the \textbf{info} command. The ASM header is a +TCL-Image header with some additions. The ASM header is defined as follows: + +\paragraph{} +In this case a word is two bytes (16 bits). The header has a +fixed size of 512 bytes. + +\begin{description} +\item[Word(s)] Contents +\item[1] Unused and always 0 in ASM. + \begin{description} + \item[\sf 0] = if file contains 16 bits pixels, `unpacked'. + \item[\sf 1] = if file contains 8 bits pixels, `packed'. + \end{description} +\item[2] Number of samples of the record. min $2^{7}=128$. max $2^{12}=4096$. +\item[3] Number of channels. min 1. max 65535. +\item[4] File sequence number on tape, starting with 1. On disk this is + always 0. +\item[5] Number of bits per sample. + \begin{description} + \item[\sf 8] = 8-bits amplitude (byte) + \item[\sf 16] = 16-bits amplitude (short) + \item[\sf 32] = 32-bits amplitude (integer) + \item[\sf 3232] = 32-bits amplitude (float) + \item[\sf 6464] = 64-bits amplitude (double) + \end{description} +\item[6] Number of records per channel. min 1. max 65535. +\item[7] Domain ID + \begin{description} + \item[\sf 0] = Time + \item[\sf 1] = Frequency + \item[\sf 2] = Amplitude + \item[\sf 3] = Magnitude + \item[\sf 4] = Phase + \end{description} +\item[8] Data Type ID + \begin{description} + \item[\sf 0] = Real + \item[\sf 1] = Imaginary + \item[\sf 2] = Complex + \end{description} +\item[9-10] Pointer to real part +\item[11-12] Pointer to imaginary part +\item[13] Samplerate in $10^{1} (Hz)$. max 65535. +\item[14-32] Reserved +\item[33-128] Numeric data (type double) +\item[129-165] ASM ID string (ASCII text) +\item[166-181] Signalname (ASCII text) +\item[182-204] User text (ASCII text) +\item[205-219] Date (ASCII text) +\item[220-256] Description (ASCII text) +\end{description} + +\section{Data} + +\paragraph{channels} +A signal can exist out of one or more channels. Channels +are in time parallel recordings of sound. This could be +done with multiple microphones. Every microphone records +a channel. A channel exists out of one or more records. +All channels have the same number of records. The maximum +number of records is 65535. + +\paragraph{records} +A channel is divided in records of equal size. The size is always +a power of 2. The minimal size is $2^{7}=128$, and the +maximal size is $2^{12}=4096$ samples. This is done to +keep the size of the data manageable. Fourier transformation is +done per record. Also displaying the signal is done per record. + +\paragraph{samples} +Samples can be real, imaginary or complex. In memory samples +are always of type double (64 bit floating point). Samples +can be converted to lower resolutions when writing them to disk. +While reading data from disk ASM will convert the samples to +type double. + +\paragraph{} +The functions in ASM generate signals that exist out of one channel +with one record. + +\begin{figure}[h] +\centerline{\includegraphics{asmdata}} +\caption{ASM file} +\label{fig:asmfile} +\end{figure} + + + +\end{document} % End of document. diff --git a/doc/asmdata.eps b/doc/asmdata.eps new file mode 100644 index 0000000..f807506 --- /dev/null +++ b/doc/asmdata.eps @@ -0,0 +1,431 @@ +%! +%%BoundingBox: 79 357 458 610 +%%Title: asmdata +%%CreationDate: Tue Oct 6 23:39:00 1998 +%%Creator: Tgif-3.0-p16 by William Chia-Wei Cheng (william@cs.UCLA.edu) + +/tgifdict 2 dict def +tgifdict begin + +end + +%%PageBoundingBox: 79 357 458 610 +tgifdict begin +/tgifsavedpage save def + +1 setmiterlimit +1 setlinewidth + +0 setgray + +72 0 mul 72 11.00 mul translate +72 128 div 100.000 mul 100 div dup neg scale + +gsave + +/tgiforigctm matrix currentmatrix def + +% BOX +0 setgray +gsave + 10 setmiterlimit + gsave + newpath + 256 328 moveto 544 328 lineto 544 768 lineto 256 768 lineto + closepath + 5 setlinewidth + stroke + grestore +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 384 moveto + 544 384 lineto + tgiforigctm setmatrix + 5 setlinewidth + stroke + 1 setlinewidth +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 576 moveto + 544 576 lineto + tgiforigctm setmatrix + 5 setlinewidth + stroke + 1 setlinewidth +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 480 moveto + 544 480 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 432 moveto + 544 432 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 528 moveto + 544 528 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 672 moveto + 544 672 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 624 moveto + 544 624 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 256 720 moveto + 544 720 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + [8 8] 0 setdash + newpath + 352 384 moveto + 352 768 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke + [] 0 setdash +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + [8 8] 0 setdash + newpath + 448 384 moveto + 448 768 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke + [] 0 setdash +grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 414 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 462 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 510 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 558 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 606 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 654 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 702 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 280 750 moveto (rec.1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 414 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 414 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 462 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 510 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 558 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 606 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 654 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 702 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 376 750 moveto (rec.2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 462 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 510 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 558 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 606 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 654 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 702 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 472 750 moveto (rec.3) show + grestore + +% TEXT +0 setgray +/Times-Bold findfont [34 0 0 -34 0 0] makefont setfont + gsave + 352 366 moveto (Header) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 414 moveto (Channel 1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 462 moveto (Channel 2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 510 moveto (Channel 3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 558 moveto (Channel 4) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 606 moveto (Channel 1) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 654 moveto (Channel 2) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 702 moveto (Channel 3) show + grestore + +% TEXT +0 setgray +/Times-Roman findfont [24 0 0 -24 0 0] makefont setfont + gsave + 144 750 moveto (Channel 4) show + grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 560 392 moveto + 576 392 lineto + 576 568 lineto + 560 568 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% POLY/OPEN-SPLINE +0 setgray +gsave + newpath + 560 584 moveto + 576 584 lineto + 576 760 lineto + 560 760 lineto + tgiforigctm setmatrix + 1 setlinewidth + stroke +grestore + +% TEXT +0 setgray +/Times-Bold findfont [34 0 0 -34 0 0] makefont setfont + gsave + 592 494 moveto (Real part) show + grestore + +% TEXT +0 setgray +/Times-Bold findfont [34 0 0 -34 0 0] makefont setfont + gsave + 592 686 moveto (Imaginary part) show + grestore + +grestore +tgifsavedpage restore +end +%MatchingCreationDate: Tue Oct 6 23:39:00 1998 diff --git a/doc/asmdata.obj b/doc/asmdata.obj new file mode 100644 index 0000000..c5ab316 --- /dev/null +++ b/doc/asmdata.obj @@ -0,0 +1,141 @@ +%TGIF 3.0-p16 +state(0,33,100.000,128,320,0,8,1,9,1,1,0,0,0,0,1,0,'Times-Roman',0,24,0,0,0,10,0,0,1,1,0,16,0,0,1,1,1,0,1088,1408,0,0,2880). +% +% @(#)$Header$ +% %W% +% +unit("1 pixel/pixel"). +color_info(11,65535,0,[ + "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, + "red", 65535, 0, 0, 65535, 0, 0, 1, + "green", 0, 65535, 0, 0, 65535, 0, 1, + "blue", 0, 0, 65535, 0, 0, 65535, 1, + "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, + "pink", 65535, 49931, 52011, 65535, 49344, 52171, 1, + "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, + "CadetBlue", 23925, 40569, 41609, 24415, 40606, 41120, 1, + "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, + "black", 0, 0, 0, 0, 0, 0, 1, + "DarkSlateGray", 11442, 19764, 19764, 12079, 20303, 20303, 1 +]). +page(1,"",1). +box('black',256,328,544,768,0,5,1,22,0,0,0,0,0,'5',[ +]). +poly('black',2,[ + 256,384,544,384],0,5,1,24,0,0,0,0,18,7,0,0,0,'5','18','7', + "0",[ +]). +poly('black',2,[ + 256,576,544,576],0,5,1,25,0,0,0,0,18,7,0,0,0,'5','18','7', + "0",[ +]). +poly('black',2,[ + 256,480,544,480],0,1,1,26,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 256,432,544,432],0,1,1,27,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 256,528,544,528],0,1,1,34,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 256,672,544,672],0,1,1,35,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 256,624,544,624],0,1,1,36,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 256,720,544,720],0,1,1,37,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 352,384,352,768],0,1,1,38,0,0,2,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',2,[ + 448,384,448,768],0,1,1,39,0,0,2,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +text('black',280,392,'Times-Roman',0,24,1,0,0,1,48,28,40,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,440,'Times-Roman',0,24,1,0,0,1,48,28,59,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,488,'Times-Roman',0,24,1,0,0,1,48,28,60,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,536,'Times-Roman',0,24,1,0,0,1,48,28,61,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,584,'Times-Roman',0,24,1,0,0,1,48,28,62,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,632,'Times-Roman',0,24,1,0,0,1,48,28,63,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,680,'Times-Roman',0,24,1,0,0,1,48,28,64,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',280,728,'Times-Roman',0,24,1,0,0,1,48,28,65,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.1"]). +text('black',376,392,'Times-Roman',0,24,1,0,0,1,48,28,66,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',472,392,'Times-Roman',0,24,1,0,0,1,48,28,68,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',376,440,'Times-Roman',0,24,1,0,0,1,48,28,70,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,488,'Times-Roman',0,24,1,0,0,1,48,28,71,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,536,'Times-Roman',0,24,1,0,0,1,48,28,72,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,584,'Times-Roman',0,24,1,0,0,1,48,28,73,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,632,'Times-Roman',0,24,1,0,0,1,48,28,74,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,680,'Times-Roman',0,24,1,0,0,1,48,28,75,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',376,728,'Times-Roman',0,24,1,0,0,1,48,28,76,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.2"]). +text('black',472,440,'Times-Roman',0,24,1,0,0,1,48,28,77,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,488,'Times-Roman',0,24,1,0,0,1,48,28,78,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,536,'Times-Roman',0,24,1,0,0,1,48,28,79,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,584,'Times-Roman',0,24,1,0,0,1,48,28,80,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,632,'Times-Roman',0,24,1,0,0,1,48,28,81,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,680,'Times-Roman',0,24,1,0,0,1,48,28,82,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',472,728,'Times-Roman',0,24,1,0,0,1,48,28,83,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "rec.3"]). +text('black',352,336,'Times-Bold',1,34,1,0,0,1,106,39,86,0,30,9,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Header"]). +text('black',144,392,'Times-Roman',0,24,1,0,0,1,101,28,92,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 1"]). +text('black',144,440,'Times-Roman',0,24,1,0,0,1,101,28,94,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 2"]). +text('black',144,488,'Times-Roman',0,24,1,0,0,1,101,28,95,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 3"]). +text('black',144,536,'Times-Roman',0,24,1,0,0,1,101,28,96,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 4"]). +text('black',144,584,'Times-Roman',0,24,1,0,0,1,101,28,97,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 1"]). +text('black',144,632,'Times-Roman',0,24,1,0,0,1,101,28,98,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 2"]). +text('black',144,680,'Times-Roman',0,24,1,0,0,1,101,28,99,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 3"]). +text('black',144,728,'Times-Roman',0,24,1,0,0,1,101,28,100,0,22,6,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Channel 4"]). +poly('black',4,[ + 560,392,576,392,576,568,560,568],0,1,1,107,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +poly('black',4,[ + 560,584,576,584,576,760,560,760],0,1,1,112,0,0,0,0,8,3,0,0,0,'1','8','3', + "0",[ +]). +text('black',592,464,'Times-Bold',1,34,1,0,0,1,135,39,113,0,30,9,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Real part"]). +text('black',592,656,'Times-Bold',1,34,1,0,0,1,220,39,115,0,30,9,0,0,0,0,0,2,0,0,0,0,"",0,0,0,[ + "Imaginary part"]). diff --git a/doc/copyright.txt b/doc/copyright.txt new file mode 100644 index 0000000..1cae98f --- /dev/null +++ b/doc/copyright.txt @@ -0,0 +1,4 @@ + +ASM is Public Domain software. + + diff --git a/doc/makefile b/doc/makefile new file mode 100644 index 0000000..6a1dfa1 --- /dev/null +++ b/doc/makefile @@ -0,0 +1,16 @@ + + +all : asm.pdf + +asm.pdf : asm.tex + latex asm.tex + latex asm.tex + dvipdfm asm.dvi + + + +clean : + rm -f asm.toc asm.log asm.aux asm.dvi asm.pdf + +distclean : + rm -f asm.toc asm.log asm.aux asm.dvi diff --git a/doc/readme.txt b/doc/readme.txt new file mode 100644 index 0000000..6e4986c --- /dev/null +++ b/doc/readme.txt @@ -0,0 +1,167 @@ + + + Another Signal Manager + + (Java version) + + + version 2.0.0 alpha1 , Oct 21 2022 + + By Erwin Waterlander + + +Contents: + + 1 What is ASM? + 2 History + 3 User interface + 4 Wishes/To do + 5 Copyright + 6 Contact/Download + +====================================================== +1 What is ASM? +====================================================== + +ASM is a program for digital signal processing for educational +purposes. + +This is a port of the original version made in 1993 by Edwin Zoer and me on an +Acorn Archimedes computer running RISC-OS. + +====================================================== +2 History +====================================================== + +AIM : ANOTHER IMAGE MANAGER + + also known as + +Atari Image Manager, +Archimedes Image Manager, +Amiga Image Manager. + +The image processing program AIM was originally developed for the +ATARI-ST by Frans Groen and Robert de Vries. Since the first +version of AIM, the improvement of this public domain image +processing package has become a joint effort of a number of +people from the Delft University of Technology and the University +of Amsterdam. +AIM has been ported to the ARCHIMEDES (Arthur version) by Robert +Ellens, Damir Sudar and Alle-Jan van der Veen. +Ed Doppenberg was successful in the port to RISC-OS. +AIM has been written in the C-language. +AIM is limited in functionality as well as in flexibility. +The main purpose of the program is to experiment with digital +image processing. + +The latest version 3.15 (1995) for Archimedes RISC-OS can be downloaded +from http://wuerthner.dyndns.org/others.html + +On the Polytechnic of Enschede the Archimedes RISC-OS version of AIM was used +in practical lessons in image processing. Polytechnic of Enschede (Hogeschool +Enschede), the Netherlands, is called Saxion hogescholen (www.saxion.nl) +today. + +ASM : ANOTHER SIGNAL MANAGER + +In 1993 the idea came to make a program like AIM, but then for signal +processing: ASM for RISC-OS. The task of our final examination for the +Polytechnic of Enschede was to create ASM for RISC-OS. + +We made ASM at and with support of the Technical University of Delft, faculty +Applied Physics, Pattern Recognition group (Tom Hoeksma), and with support from +the Technisch Physische Dienst, Delft (Ed Doppenberg). Our starting point was +a stripped down version of AIM made by Ed Doppenberg. It was only one window +with a command line interpreter. + +In 1993 Edwin and I had only basic knowledge of ANSI C and no knowledge about +making user interfaces for RISC-OS. Our goal was to put as much as possible +functionality in the program in only three months. + +With the first RISC-OS version we created it was possible to generate signals +and do some basic processing on them. The program was made for use during +practical lessons in digital signal processing at the polytechnic in Enschede. + +The original intention was that other students would develop ASM further. But +it was Ed Doppenberg who did a thorough revision of the source code and added +some professional functionality. That version of ASM (for RISC-OS) is not free +available for the public domain. + +In 1997 I ported the first version of ASM for RISC-OS to DOS using DJGPP 2.01 +(gcc 2.7.2). See djgpp.txt. I used the Allegro 2.2 graphics library. +Allegro is a library intended for use in computer games. It was initially +conceived on the Atari ST. See allegro.txt. + +In 1997 my primary goal was to port the program to a working version on DOS, for +the fun of programming and because I had no Archimedes computer. That means I +only changed the graphical interface. I tried to keep the source code as much +as possible the same. There are large changes in file plotutil.c. Files aim.c +and command.c have been replaced by asm.c. + +Allegro development went on, supporting more platforms. In 2007 I build ASM +also for Windows and Linux. I replaced some deprecated Allegro api calls with +new ones, and build ASM for DOS, Windows and Linux. A few minor problems have +been fixed. For the rest it's the same version as in 1997. + +For many years I had in the back of my mind the idea to make a windowed +version, like the original version on RiscOS. In 2021 I started porting ASM to +Java. In Oct 2022 the first alpha version was ready. + +====================================================== +3 User interface +====================================================== + +Graphical interface + +ASM for RISC-OS has a windowed interface. One command line window and +each signal shown in a separate window with scroll bars. + +Due to the limitations of DOS (no window environment) I had to change the +graphical interface. ASM for DOS can display only one signal at a time. Other +signals stay resident in memory. + +The Java version has a windowed interface. It also adds menus for most of the +commands. + + +Command line interface + +ASM has the same command line interface as AIM. + +Commands can be abbreviated as long as they stay unique. + +Parameters are separated by spaces. +If you don't give all the parameters that are possible on +a certain command ASM will take default values. + + +====================================================== +4 Wishes/To do +====================================================== + +- Better and more support of wave sound fils + (RIFF WAV format). + Read, write, play. + + +====================================================== +5 Copyright +====================================================== + +ASM is Public Domain software. + +====================================================== +6 Contact/Download +====================================================== + +ASM and a manual in PDF format +can be downloaded from: +https://waterlan.home.xs4all.nl/ + +Erwin Waterlander +Eindhoven +The Netherlands +e-mail : waterlan@xs4all.nl + +Remarks are welcome. diff --git a/doc/todo.txt b/doc/todo.txt new file mode 100644 index 0000000..8bd59f6 --- /dev/null +++ b/doc/todo.txt @@ -0,0 +1,92 @@ +sources.c DONE + v int FnoiseCi(char *p) + v int FsineCi (char *s) + v int FsinecCi(char *p) + v int FcosineCi(char *p) + v int FexpCi(char *p) + v int FsquarewaveCi(char *p) + v int FtriangleCi(char *p) + v int FconstCi(char *p) + v int FstepCi(char *p) + v int FdeltaCi(char *p) + v int FrampCi(char *p) + v int WhanningCi(char *p) + v int WhammingCi(char *p) + v int WgaussCi(char *p) + v int WblackmanCi(char *p) + v int WkaiserCi(char *p) + v int WtriangleCi(char *p) + v wblock() extra + +calculat.c + v int ClearCi(char *p) + v int AssignCi(char *p) + v int CmultiplyCi(char *p) + v int CdivideCi(char *p) + v int CabsCi(char *p) + v int CaddCi(char *p) + v int InvCi(char *p) + v int ConjugateCi(char *p) + v int AddCi(char *p) + v int SubCi(char *p) + v int MultiplyCi(char *p) + v int DivideCi(char *p) + v int AbsoluteCi(char *p) + v int LnCi(char *p) + v int LogCi(char *p) + v int EpowCi(char *p) + v int TenpowCi(char *p) + v int SineCi(char *p) + v int CosineCi(char *p) + v int MinimumCi(char *p) + v int MaximumCi(char *p) + v int ZeropadCi(char *p) + v int ShiftCi(char *p) + v int RotateCi(char *p) + v int ClipCi(char *p) + +transfor.c + v int FFTCi(char *p) + v int IFFTCi(char *p) + v int MagnitudeCi (char *p) + v int PhaseCi (char *p) + +convcorr.c + v ConvolutionCi + V CorrelationCi + +commnd1.c + v QuitCi + v ListComCi + v HistCi + v WriteCi + v ReadCi + v RenameCi + BitmapCi New + SamplerateCi New + SignaldirCi New + MacroCi New + DosshellCi New + +plotcomm.c + v XscaleCi + v CopyCi + v ImagCi + v RealCi + v BodeCi + v DoffCi + v DonCi + v BoffCi + v BonCi + v DisplayCi + v InfoCi + v PrintCi + v ListCi + +sound.c + ReadWav.Ci New + + +Ander: + v Magnitude draw: clip at -100 dB + diff --git a/doc/whatsnew.txt b/doc/whatsnew.txt new file mode 100644 index 0000000..fce08cf --- /dev/null +++ b/doc/whatsnew.txt @@ -0,0 +1,142 @@ +Oct 21 2022: Version 2.0.0-alpha1 + + - Rewrote ASM in Java using JavaFX graphics. + - Each signal is shown in its own window. + - Menus and dialogs for each command. + - Fixed bode magnitude plot for very low values. Plot is cut at -100 dB. + + +Jul 1 2022: Version 1.1.3 + + In 2021 I started porting ASM to Java + JavaFX to make a good interface. + During this work I found a some bugs which are fixed in this version. + + This is the last C based version. Development will go on in the Java + version. + + + - Fixed high CPU load when waiting for input. + - Fixed wrong values at Y-axis when the maximum value was smaller than + the absolute minimal value. + - Fixed Blackman, Hamming, Hanning, and Kaiser windows. + - Added missing command for window Block. + - Fixed shift function for signals with more than one record. + - Fixed rotate function for negative rotation. + - Fixed command description of correlation and convolution in the manual. + - Updated doc/makefile for PDF generation from LaTeX. + - Removed the PostScript documentation file. + - The default sample rate is 10240 Hz. + - The default screen resolution is 1024x768. + + The following keyboard shortcuts have been added (The Escape key and + several function keys of my laptop are broken :) ). + + - ALT-X and CTRL-C bring you to the title screen. + - SHIFT- and SHIFT- show the previous and next signal. + - CTRL- and CTRL- to zoom out and in. + + Removed the DOS and Linux binaries. + The Windows binary has been built with MinGW-w64 gcc 4.9.2 (i686-w64-mingw32) + and Allegro 4.4.2. I was not able to build Allegro 4.4.2 myself anymore. I took + the Allegro 4.4.2 binary package for MinGW 4.5.2 from https://www.allegro.cc/ + + +Jul 28 2015: Version 1.1.2 + + I did not look at ASM for a long time. I noticed the Windows compiled + program does not run on Windows 8, so I recompiled it with newer tools. + + - Fixed slow printing of text on Windows. + - Keys and now scroll the displayed signal left and right. + - Removed i586 (Pentium) target from makefiles. + - Use MinGW-w64 32 bit compiler from the MSYS2 project. + http://sourceforge.net/projects/msys2 + Using gcc 4.9.2, Target: i686-w64-mingw32 + - Use Allegro 4.4.2 library. + MSYS2 already includes DirectX. No need to use dx70_mgw.zip. + To build Allegro with MSYS2 do: + + mkdir Build; cd Build + cmake \ + -G "MSYS Makefiles" \ + -DCMAKE_SYSTEM_PREFIX_PATH:PATH=/mingw32/i686-w64-mingw32/ \ + .. + make ; make install + + + If I had more time I would make a good + interface using the QT library. + + +Sep 8 2007: Version 1.1.1 + + - Updated documentation, chapter Introduction. + + +Jun 27 2007: version 1.1 + + - Use Allegro 4.2.1 library. + - Fix buffer overflow, in signal name. + - Signal image can be saved in BMP format. + - Target Pentium processor. + - Build new Windows and Linux version. + - Rebuild DOS version. + - Updated documentation. + - The following compilers have been used: + DOS : DJGPP 2.03, gcc 3.4.4 + Windows: MinGW 4.1, gcc 3.4.2 + Linux : Red Hat Linux 9.0, gcc 3.2.2 + + +Oct 8 1998: Version 1.0 + + - Retyped the documentation in a condensed version in LaTeX. + The original documentation was written on an Acorn Archimedes + computer, in Dutch. I have only a paper copy. + Added PostScript and PDF documents. + +Aug 25 1997 + + - Caluculation functons copy the HScale factor of the source + signal to the target signal. + +Aug 20 1997 + + - readwav command added. + +Aug 19 1997 + + - Command and poll prompt added. + +Aug 11 1997 + + - recompiled Allegro library. + FIX_SHIFT define in file misc.s set 16. + +Jul 18 1997 + + - Function XscaleCi in plotcomm.c + 1. Build in check for scalefactor, may not be zero. This + can happen if you type by accident e.g. xscale 0,5 + in stead of xscale 0.5 + - Function LnCi and LogCi in calculat.c + 1. check if the signal has values that are negative or zero. + +Jul 17 1997 + + - Function BitmapCi in commnd1.c + 1. Function saved image always in PCX format. + 2. It's possible to save only in PCX and TGA format, + not BMP. + - Function Dossshell in commnd1.c + 1. Function always called "command.com" as the dos-shell. + Now is calls wat the COMSPEC environment variable is. + +Jul 16 1997: Version 1.0 beta. + + First version of ASM for DOS. + Used DJGPP (gcc 2.7.2) and Allegro graphical library (version 2.2). + +1993 + + Initial version on Acorn Archimedes RISC-OS.