/************************************************************************/ /* */ /* ecgApplet.java */ /* */ /* Copyright (C) 2003 Mauricio Villarroel */ /* (mauricio DOT vllarroel AT estudiantes DOT ucb DOT edu DOT bo) */ /* */ /* ecgApplet.java and all its components are free software; you can */ /* redistribute them and/or modify it under the terms of the */ /* GNU General Public License as published by the Free Software */ /* Foundation; either version 2 of the License, or (at your option) */ /* any later version. */ /* */ /* This file is distributed in the hope that it will be useful, but */ /* WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* See the GNU General Public License for more details. */ /* */ /************************************************************************/ /* */ /* This file was created for the ECGSYN Application. */ /* */ /* ECGSYN: A program for generating a realistic synthetic */ /* Electrocardiogram Signals. */ /* Copyright (c) 2003 by Patrick McSharry & Gari Clifford. */ /* All rights reserved. */ /* */ /* See IEEE Transactions On Biomedical Engineering, */ /* 50(3), 289-294, March 2003. */ /* Contact: */ /* P. McSharry (patrick AT mcsharry DOT net) */ /* G. Clifford (gari AT mit DOT edu) */ /* */ /************************************************************************/ /* */ /* Further updates to this software will be published on: */ /* http://www.physionet.org/ */ /* */ /************************************************************************/ import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.text.*; import java.util.Vector; import java.io.File; import java.io.IOException; import java.awt.event.*; import java.lang.Math.*; import java.util.Timer; import java.util.TimerTask; /* * This class formats a number in decimal notation or in * scientific notation. */ class FormatNumber{ final static DecimalFormat dec1 = new DecimalFormat("0.0"); final static DecimalFormat dec2 = new DecimalFormat("0.00"); final static DecimalFormat sci1 = new DecimalFormat("0.0E0"); final static DecimalFormat sci2 = new DecimalFormat("0.00E0"); /* * Formats the 'number' parameter and returns it as a String. * precision = number of decimal places in the output. */ public static String toString( double number, double upLimit, double loLimit, int precision) { // If number less than decimalLimit, or equal to zero, use decimal style if( number == 0.0 || (Math.abs(number) <= upLimit && Math.abs(number) > loLimit) ) { switch (precision){ case 1 : return dec1.format(number); case 2 : return dec2.format(number); default: return dec1.format(number); } } else{ // Create the format for Scientific Notation with E switch (precision){ case 1 : return sci1.format(number); case 2 : return sci2.format(number); default: return sci1.format(number); } } } } /* * * Public main class */ public class ecgApplet extends javax.swing.JApplet implements AdjustmentListener{ /************************************** * Colors for the Plotting Components * **************************************/ protected Color ecgPlotColor = Color.BLUE; protected Color frameLineColor = Color.BLACK; protected Color frameInsideLineColor = Color.LIGHT_GRAY; protected Color frameFillColor = Color.WHITE; protected Color axesNumColor = Color.GRAY; protected Color titleColor = Color.BLACK; protected Color bgColor = Color.WHITE; /********************************************* * These constants used in drawText() method * for placement of the text within a given * rectangular area. *********************************************/ final int CENTER = 0; final int LEFT = 1; final int RIGHT = 2; /******************* * Frame Dimensions. *******************/ final int posFrameX =0; final int posFrameY =1; final int frameHeight =290; final int frameAmplitude = frameHeight/2; //Coordinates Origin final int posOriginY = posFrameY + (frameHeight/2); //X coordinates final int horzScaleY = posFrameY + frameHeight; final int horzScaleWidth = 100; final int horzScaleHeight = 20; final int fScaleNumSize = 9; /**************************************************** * Limit below which scale values use decimal format, * above which they use scientific format. ****************************************************/ double upLimit = 100.0; double loLimit = 0.01; /****************************** * Ploting variables ******************************/ boolean readyToPlot; int plotScrollBarValue; double plotZoom = 0.008; double plotZoomInc = 2; /* Flag Variable, show if data has been generated. */ private boolean ecgGenerated = false; /**************************************************************** * GLOBAL ECG PARAMETERS: ****************************************************************/ private int N; /* Number of heart beats */ private double hrstd; /* Heart rate std */ private double hrmean; /* Heart rate mean */ private double lfhfratio; /* LF/HF ratio */ private int sfecg; /* ECG sampling frequency */ private int sf; /* Internal sampling frequency */ private double amplitude; /* Amplitude for the plot area */ private int seed; /* Seed */ private double Anoise; /* Amplitude of additive uniform noise*/ private int period; /* Define frequency parameters for rr process * flo and fhi correspond to the Mayer waves and respiratory rate respectively */ private double flo; /* Low frequency */ private double fhi; /* High frequency */ private double flostd; /* Low frequency std */ private double fhistd; /* High frequency std */ /* Order of extrema: [P Q R S T] */ private double[] theta = new double[6]; /* ti not in radians*/ private double[] a = new double[6]; private double[] b = new double[6]; /******************************* * Variable for the Data table *******************************/ private String[] peakStr = {"", "P", "Q", "R", "S", "T"}; /****************************************** * Variables to Animate ECG ******************************************/ //Animating in process? private boolean ecgAnimateFlg =false; Timer ecgAnimateTimer; private long ecgAnimateInterval; /* Total plotting Data Table Row */ private int ecgAnimateNumRows; /* Current plotting Data Table Row */ private int ecgAnimateCurRow; /* Plot Area Panel width */ private int ecgAnimatePanelWidth; /* Starting X axis value to plot*/ private int ecgAnimateInitialZero; /* For plotting */ Point ecgAnimateLastPoint = new java.awt.Point(0, 0); /** Initializes the applet ecgApplet */ public void init() { initComponents(); initWindow(); } private void initWindow(){ /********************* *Init the main Window *Set maximize *********************/ try{ ecgWindow.setMaximum(true); } catch(java.beans.PropertyVetoException e){ txtStatus.append("Exception Error : " + e + "\n"); } /********************* *Init the data Table *********************/ tableValuesModel = new DefaultTableModel( new Object [][] {}, new String [] {"Time", "Voltage", "Peak"}){ Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.String.class }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } }; tableValues.setModel(tableValuesModel); /* Init the ecgFrame */ ecgFrame = new ecgPanel(); ecgFrame.setBackground(new java.awt.Color(255, 255, 255)); ecgPlotArea.setViewportView(ecgFrame); /* Set the ScrollBar */ plotScrollBar.addAdjustmentListener(this); /* Set the size of the Dialogs */ paramDialog.setBounds(80, 80, 570,500); alert.setBounds(80, 80, 540,200); helpDialog.setBounds(80, 80, 600,500); /************************* * Reset all Application * to a init state. *************************/ resetECG(); } private void initComponents() {//GEN-BEGIN:initComponents paramDialog = new javax.swing.JDialog(); paramDesktopPane = new javax.swing.JDesktopPane(); closeParamDialogButton = new javax.swing.JButton(); resetParamDialogButton = new javax.swing.JButton(); saveParamDialogButton = new javax.swing.JButton(); paramTabbedPane = new javax.swing.JTabbedPane(); generalInterfacePanel = new javax.swing.JPanel(); txtSf = new javax.swing.JTextField(); lblSf = new javax.swing.JLabel(); lblN = new javax.swing.JLabel(); txtN = new javax.swing.JTextField(); lblHrmean = new javax.swing.JLabel(); txtHrmean = new javax.swing.JTextField(); lblHrstd = new javax.swing.JLabel(); txtHrstd = new javax.swing.JTextField(); lblAmplitude = new javax.swing.JLabel(); txtAmplitude = new javax.swing.JTextField(); lblGeneralTitle = new javax.swing.JLabel(); lblAnoise = new javax.swing.JLabel(); txtAnoise = new javax.swing.JTextField(); lblSfecg = new javax.swing.JLabel(); txtSfecg = new javax.swing.JTextField(); lblSeed = new javax.swing.JLabel(); txtSeed = new javax.swing.JTextField(); spectralCharacteristicsPanel = new javax.swing.JPanel(); lblSpectralTitle = new javax.swing.JLabel(); lblLfhfratio = new javax.swing.JLabel(); txtLfhfratio = new javax.swing.JTextField(); lblFlo = new javax.swing.JLabel(); txtFlo = new javax.swing.JTextField(); lblFhi = new javax.swing.JLabel(); txtFhi = new javax.swing.JTextField(); lblFlostd = new javax.swing.JLabel(); lblFhistd = new javax.swing.JLabel(); txtFhistd = new javax.swing.JTextField(); txtFlostd = new javax.swing.JTextField(); extremaPanel = new javax.swing.JPanel(); lblMorphologyTitle = new javax.swing.JLabel(); tiScrollPane = new javax.swing.JScrollPane(); tiTable = new javax.swing.JTable(); aiScrollPane = new javax.swing.JScrollPane(); aiTable = new javax.swing.JTable(); biScrollPane = new javax.swing.JScrollPane(); biTable = new javax.swing.JTable(); ExtremaLabelScrollPane = new javax.swing.JScrollPane(); ExtremaLabelTable = new javax.swing.JTable(); paramHelpButton = new javax.swing.JButton(); alert = new javax.swing.JDialog(); alertDesktopPane = new javax.swing.JDesktopPane(); alertText = new javax.swing.JTextArea(); alertButton = new javax.swing.JButton(); alertTitle = new javax.swing.JLabel(); exportDialog = new javax.swing.JDialog(); helpDialog = new javax.swing.JDialog(); helpInternalFrame = new javax.swing.JInternalFrame(); helpScrollPane = new javax.swing.JScrollPane(); helpEditorPane = new javax.swing.JEditorPane(); ecgWindow = new javax.swing.JInternalFrame(); desktopPane = new javax.swing.JDesktopPane(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); jLabel5 = new javax.swing.JLabel(); jLabel6 = new javax.swing.JLabel(); jLabel7 = new javax.swing.JLabel(); lblMaxAmplitude = new javax.swing.JLabel(); lblOrigin = new javax.swing.JLabel(); lblMinAmplitude = new javax.swing.JLabel(); lblXAxis = new javax.swing.JLabel(); TableScrollPane = new javax.swing.JScrollPane(); tableValues = new javax.swing.JTable(); exportButton = new javax.swing.JButton(); plotScrollBar = new javax.swing.JScrollBar(); statusScrollPane = new javax.swing.JScrollPane(); txtStatus = new javax.swing.JTextArea(); ecgPlotArea = new javax.swing.JScrollPane(); animateDesktopPane = new javax.swing.JDesktopPane(); stopAnimateButton = new javax.swing.JButton(); startAnimateButton = new javax.swing.JButton(); calculateDesktopPane = new javax.swing.JDesktopPane(); generateButton = new javax.swing.JButton(); clearButton = new javax.swing.JButton(); paramButton = new javax.swing.JButton(); zommDesktopPane = new javax.swing.JDesktopPane(); zoomInButton = new javax.swing.JButton(); zoomOutButton = new javax.swing.JButton(); paramDialog.setTitle("Set ECG Parameters..."); paramDialog.setName("paramDialog"); closeParamDialogButton.setText("Close"); closeParamDialogButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { closeParamDialogButtonActionPerformed(evt); } }); closeParamDialogButton.setBounds(416, 400, 140, 30); paramDesktopPane.add(closeParamDialogButton, javax.swing.JLayeredPane.DEFAULT_LAYER); resetParamDialogButton.setText("Reset Values"); resetParamDialogButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { resetParamDialogButtonActionPerformed(evt); } }); resetParamDialogButton.setBounds(160, 400, 140, 30); paramDesktopPane.add(resetParamDialogButton, javax.swing.JLayeredPane.DEFAULT_LAYER); saveParamDialogButton.setText("Save Values"); saveParamDialogButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveParamDialogButtonActionPerformed(evt); } }); saveParamDialogButton.setBounds(7, 400, 140, 30); paramDesktopPane.add(saveParamDialogButton, javax.swing.JLayeredPane.DEFAULT_LAYER); paramTabbedPane.setBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED)); paramTabbedPane.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT); generalInterfacePanel.setLayout(null); generalInterfacePanel.setName("generalInterface"); txtSf.setToolTipText(""); txtSf.setInputVerifier(new sfVerifier()); generalInterfacePanel.add(txtSf); txtSf.setBounds(350, 110, 110, 20); lblSf.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblSf.setText("Internal Sampling frequency [Hz]"); generalInterfacePanel.add(lblSf); lblSf.setBounds(10, 110, 320, 16); lblN.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblN.setText("Approximate number of heart beats"); generalInterfacePanel.add(lblN); lblN.setBounds(10, 50, 320, 16); txtN.setToolTipText(""); txtN.setInputVerifier(new integerVerifier()); generalInterfacePanel.add(txtN); txtN.setBounds(350, 50, 110, 20); lblHrmean.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblHrmean.setText("Heart rate mean [bpm]"); generalInterfacePanel.add(lblHrmean); lblHrmean.setBounds(10, 170, 320, 16); txtHrmean.setToolTipText(""); txtHrmean.setInputVerifier(new doubleVerifier()); generalInterfacePanel.add(txtHrmean); txtHrmean.setBounds(350, 170, 110, 20); lblHrstd.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblHrstd.setText("Heart rate standard deviation [bpm]"); generalInterfacePanel.add(lblHrstd); lblHrstd.setBounds(10, 200, 320, 16); txtHrstd.setToolTipText(""); txtHrstd.setInputVerifier(new doubleVerifier()); generalInterfacePanel.add(txtHrstd); txtHrstd.setBounds(350, 200, 110, 20); lblAmplitude.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblAmplitude.setText("Plot area Amplitude"); generalInterfacePanel.add(lblAmplitude); lblAmplitude.setBounds(10, 260, 320, 16); txtAmplitude.setToolTipText(""); txtAmplitude.setInputVerifier(new doubleVerifier()); generalInterfacePanel.add(txtAmplitude); txtAmplitude.setBounds(350, 260, 110, 20); lblGeneralTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); lblGeneralTitle.setText("General Interface Parameters..."); generalInterfacePanel.add(lblGeneralTitle); lblGeneralTitle.setBounds(120, 10, 350, 20); lblAnoise.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblAnoise.setText("Amplitude of additive uniform noise [mV]"); lblAnoise.setToolTipText(""); generalInterfacePanel.add(lblAnoise); lblAnoise.setBounds(10, 140, 320, 16); txtAnoise.setToolTipText(""); txtAnoise.setInputVerifier(new doubleVerifier()); txtAnoise.setName("Anoise"); generalInterfacePanel.add(txtAnoise); txtAnoise.setBounds(350, 140, 110, 20); lblSfecg.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblSfecg.setText("ECG Sampling Frequency [Hz]"); generalInterfacePanel.add(lblSfecg); lblSfecg.setBounds(10, 80, 320, 16); txtSfecg.setToolTipText(""); txtSfecg.setInputVerifier(new sfecgVerifier()); generalInterfacePanel.add(txtSfecg); txtSfecg.setBounds(350, 80, 110, 20); lblSeed.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblSeed.setText("Seed"); generalInterfacePanel.add(lblSeed); lblSeed.setBounds(10, 230, 320, 16); txtSeed.setToolTipText(""); txtSeed.setInputVerifier(new integerVerifier()); generalInterfacePanel.add(txtSeed); txtSeed.setBounds(350, 230, 110, 20); paramTabbedPane.addTab("General Interface", generalInterfacePanel); spectralCharacteristicsPanel.setLayout(null); spectralCharacteristicsPanel.setName("spectralCharacteristics"); lblSpectralTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); lblSpectralTitle.setText("Spectral Characteristics Parameters..."); spectralCharacteristicsPanel.add(lblSpectralTitle); lblSpectralTitle.setBounds(120, 10, 350, 20); lblLfhfratio.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblLfhfratio.setText("LF/HF ratio"); spectralCharacteristicsPanel.add(lblLfhfratio); lblLfhfratio.setBounds(10, 170, 320, 16); txtLfhfratio.setToolTipText("Low Frequency / High Frequency ratio"); txtLfhfratio.setInputVerifier(new doubleVerifier()); spectralCharacteristicsPanel.add(txtLfhfratio); txtLfhfratio.setBounds(350, 170, 110, 20); lblFlo.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblFlo.setText("Low frequency [Hz]"); spectralCharacteristicsPanel.add(lblFlo); lblFlo.setBounds(10, 50, 320, 16); txtFlo.setToolTipText(""); txtFlo.setInputVerifier(new doubleVerifier()); spectralCharacteristicsPanel.add(txtFlo); txtFlo.setBounds(350, 50, 110, 20); lblFhi.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblFhi.setText("High frequency [Hz]"); spectralCharacteristicsPanel.add(lblFhi); lblFhi.setBounds(10, 80, 320, 16); txtFhi.setToolTipText(""); txtFhi.setInputVerifier(new doubleVerifier()); spectralCharacteristicsPanel.add(txtFhi); txtFhi.setBounds(350, 80, 110, 20); lblFlostd.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblFlostd.setText("Low frequency standard deviation [Hz]"); spectralCharacteristicsPanel.add(lblFlostd); lblFlostd.setBounds(10, 110, 320, 16); lblFhistd.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblFhistd.setText("High frequency standard deviation [Hz]"); lblFhistd.setToolTipText(""); spectralCharacteristicsPanel.add(lblFhistd); lblFhistd.setBounds(10, 140, 320, 16); txtFhistd.setToolTipText(""); txtFhistd.setInputVerifier(new doubleVerifier()); txtFhistd.setName("Anoise"); spectralCharacteristicsPanel.add(txtFhistd); txtFhistd.setBounds(350, 140, 110, 20); txtFlostd.setToolTipText(""); txtFlostd.setInputVerifier(new doubleVerifier()); spectralCharacteristicsPanel.add(txtFlostd); txtFlostd.setBounds(350, 110, 110, 20); paramTabbedPane.addTab("Spectral Characteristics", spectralCharacteristicsPanel); extremaPanel.setLayout(null); lblMorphologyTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); lblMorphologyTitle.setText("Order of Extrema..."); extremaPanel.add(lblMorphologyTitle); lblMorphologyTitle.setBounds(90, 10, 350, 20); tiScrollPane.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); tiScrollPane.setViewportBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); tiTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null}, {null}, {null}, {null}, {null} }, new String [] { "Theta" } ) { Class[] types = new Class [] { java.lang.Double.class }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } }); tiScrollPane.setViewportView(tiTable); extremaPanel.add(tiScrollPane); tiScrollPane.setBounds(170, 80, 80, 120); aiScrollPane.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); aiScrollPane.setViewportBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); aiTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null}, {null}, {null}, {null}, {null} }, new String [] { "a" } ) { Class[] types = new Class [] { java.lang.Double.class }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } }); aiScrollPane.setViewportView(aiTable); extremaPanel.add(aiScrollPane); aiScrollPane.setBounds(280, 80, 80, 120); biScrollPane.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); biScrollPane.setViewportBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); biTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null}, {null}, {null}, {null}, {null} }, new String [] { "b" } ) { Class[] types = new Class [] { java.lang.Double.class }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } }); biScrollPane.setViewportView(biTable); extremaPanel.add(biScrollPane); biScrollPane.setBounds(390, 80, 80, 120); ExtremaLabelScrollPane.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); ExtremaLabelScrollPane.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); ExtremaLabelScrollPane.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_NEVER); ExtremaLabelScrollPane.setViewportBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); ExtremaLabelScrollPane.setEnabled(false); ExtremaLabelTable.setBackground((java.awt.Color) javax.swing.UIManager.getDefaults().get("Button.background")); ExtremaLabelTable.setFont(new java.awt.Font("Dialog", 1, 12)); ExtremaLabelTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {" P(1) :"}, {" Q(2) :"}, {" R(3) :"}, {" S(4) :"}, {" T(5) :"} }, new String [] { "peak label" } ) { Class[] types = new Class [] { java.lang.String.class }; boolean[] canEdit = new boolean [] { false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); ExtremaLabelTable.setGridColor((java.awt.Color) javax.swing.UIManager.getDefaults().get("Button.background")); ExtremaLabelTable.setEnabled(false); ExtremaLabelScrollPane.setViewportView(ExtremaLabelTable); extremaPanel.add(ExtremaLabelScrollPane); ExtremaLabelScrollPane.setBounds(40, 80, 110, 120); paramTabbedPane.addTab("ECG Morphology", extremaPanel); paramTabbedPane.setBounds(7, 10, 550, 380); paramDesktopPane.add(paramTabbedPane, javax.swing.JLayeredPane.DEFAULT_LAYER); paramHelpButton.setText("Help"); paramHelpButton.setEnabled(false); paramHelpButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { paramHelpButtonActionPerformed(evt); } }); paramHelpButton.setBounds(310, 400, 100, 30); paramDesktopPane.add(paramHelpButton, javax.swing.JLayeredPane.DEFAULT_LAYER); paramDialog.getContentPane().add(paramDesktopPane, java.awt.BorderLayout.CENTER); alert.setModal(true); alertText.setBackground((java.awt.Color) javax.swing.UIManager.getDefaults().get("Desktop.background")); alertText.setEditable(false); alertText.setLineWrap(true); alertText.setRows(10); alertText.setWrapStyleWord(true); alertText.setBounds(10, 10, 520, 80); alertDesktopPane.add(alertText, javax.swing.JLayeredPane.DEFAULT_LAYER); alertButton.setText("OK"); alertButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { alertButtonActionPerformed(evt); } }); alertButton.setBounds(230, 110, 80, -1); alertDesktopPane.add(alertButton, javax.swing.JLayeredPane.DEFAULT_LAYER); alertTitle.setBounds(0, 0, 350, -1); alertDesktopPane.add(alertTitle, javax.swing.JLayeredPane.DEFAULT_LAYER); alert.getContentPane().add(alertDesktopPane, java.awt.BorderLayout.CENTER); exportDialog.setModal(true); helpInternalFrame.setTitle("ECG Help"); helpInternalFrame.setVisible(true); helpEditorPane.setEditable(false); helpScrollPane.setViewportView(helpEditorPane); helpInternalFrame.getContentPane().add(helpScrollPane, java.awt.BorderLayout.CENTER); helpDialog.getContentPane().add(helpInternalFrame, java.awt.BorderLayout.CENTER); setFocusCycleRoot(false); setName("ecgpanel"); ecgWindow.setBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED)); ecgWindow.setTitle("Electrocardiogram Signals (ECG)"); try { ecgWindow.setSelected(true); } catch (java.beans.PropertyVetoException e1) { e1.printStackTrace(); } ecgWindow.setVisible(true); jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel1.setText("V"); jLabel1.setBounds(0, 110, 20, 16); desktopPane.add(jLabel1, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel2.setText("o"); jLabel2.setBounds(0, 130, 20, 16); desktopPane.add(jLabel2, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel3.setText("l"); jLabel3.setBounds(0, 150, 20, 16); desktopPane.add(jLabel3, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel4.setText("t"); jLabel4.setBounds(0, 170, 20, 16); desktopPane.add(jLabel4, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel5.setText("a"); jLabel5.setBounds(0, 190, 20, 16); desktopPane.add(jLabel5, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel6.setText("g"); jLabel6.setBounds(0, 210, 20, 16); desktopPane.add(jLabel6, javax.swing.JLayeredPane.DEFAULT_LAYER); jLabel7.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel7.setText("e"); jLabel7.setBounds(0, 230, 20, 16); desktopPane.add(jLabel7, javax.swing.JLayeredPane.DEFAULT_LAYER); lblMaxAmplitude.setFont(new java.awt.Font("Dialog", 1, 9)); lblMaxAmplitude.setText("0.001"); lblMaxAmplitude.setBounds(30, 25, 40, 12); desktopPane.add(lblMaxAmplitude, javax.swing.JLayeredPane.DEFAULT_LAYER); lblOrigin.setFont(new java.awt.Font("Dialog", 1, 9)); lblOrigin.setText("0.00"); lblOrigin.setBounds(30, 167, 40, 12); desktopPane.add(lblOrigin, javax.swing.JLayeredPane.DEFAULT_LAYER); lblMinAmplitude.setFont(new java.awt.Font("Dialog", 1, 9)); lblMinAmplitude.setText("-0.001"); lblMinAmplitude.setBounds(30, 309, 40, 12); desktopPane.add(lblMinAmplitude, javax.swing.JLayeredPane.DEFAULT_LAYER); lblXAxis.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); lblXAxis.setText("Time"); lblXAxis.setBounds(73, 367, 580, 16); desktopPane.add(lblXAxis, javax.swing.JLayeredPane.DEFAULT_LAYER); TableScrollPane.setBorder(new javax.swing.border.TitledBorder(null, "Data Table", javax.swing.border.TitledBorder.CENTER, javax.swing.border.TitledBorder.ABOVE_TOP)); TableScrollPane.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); TableScrollPane.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); tableValues.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF); TableScrollPane.setViewportView(tableValues); TableScrollPane.setBounds(658, 2, 250, 510); desktopPane.add(TableScrollPane, javax.swing.JLayeredPane.DEFAULT_LAYER); exportButton.setText("Export Table Data..."); exportButton.setEnabled(false); exportButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { exportButtonActionPerformed(evt); } }); exportButton.setBounds(658, 515, 250, 20); desktopPane.add(exportButton, javax.swing.JLayeredPane.DEFAULT_LAYER); plotScrollBar.setMaximum(0); plotScrollBar.setOrientation(javax.swing.JScrollBar.HORIZONTAL); plotScrollBar.setName("timeScroll"); plotScrollBar.setBounds(73, 352, 580, 17); desktopPane.add(plotScrollBar, javax.swing.JLayeredPane.DEFAULT_LAYER); statusScrollPane.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), "Status and Messages:", javax.swing.border.TitledBorder.LEFT, javax.swing.border.TitledBorder.ABOVE_TOP)); statusScrollPane.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); txtStatus.setEditable(false); statusScrollPane.setViewportView(txtStatus); statusScrollPane.setBounds(234, 385, 420, 150); desktopPane.add(statusScrollPane, javax.swing.JLayeredPane.DEFAULT_LAYER); ecgPlotArea.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), "Plot Area", javax.swing.border.TitledBorder.CENTER, javax.swing.border.TitledBorder.ABOVE_TOP)); ecgPlotArea.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); ecgPlotArea.setVerticalScrollBarPolicy(javax.swing.JScrollPane.VERTICAL_SCROLLBAR_NEVER); ecgPlotArea.setBounds(73, 2, 580, 350); desktopPane.add(ecgPlotArea, javax.swing.JLayeredPane.DEFAULT_LAYER); animateDesktopPane.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)), "Animate")); stopAnimateButton.setFont(new java.awt.Font("Dialog", 1, 11)); stopAnimateButton.setText("Stop"); stopAnimateButton.setEnabled(false); stopAnimateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { stopAnimateButtonActionPerformed(evt); } }); stopAnimateButton.setBounds(120, 17, 90, 20); animateDesktopPane.add(stopAnimateButton, javax.swing.JLayeredPane.DEFAULT_LAYER); startAnimateButton.setFont(new java.awt.Font("Dialog", 1, 11)); startAnimateButton.setText("Start"); startAnimateButton.setEnabled(false); startAnimateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { startAnimateButtonActionPerformed(evt); } }); startAnimateButton.setBounds(7, 17, 90, 20); animateDesktopPane.add(startAnimateButton, javax.swing.JLayeredPane.DEFAULT_LAYER); animateDesktopPane.setBounds(7, 492, 220, 45); desktopPane.add(animateDesktopPane, javax.swing.JLayeredPane.DEFAULT_LAYER); calculateDesktopPane.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)), "Calculate ECG")); generateButton.setFont(new java.awt.Font("Dialog", 1, 11)); generateButton.setText("Generate"); generateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { generateButtonActionPerformed(evt); } }); generateButton.setBounds(7, 17, 90, 20); calculateDesktopPane.add(generateButton, javax.swing.JLayeredPane.DEFAULT_LAYER); clearButton.setFont(new java.awt.Font("Dialog", 1, 11)); clearButton.setText("Clear"); clearButton.setEnabled(false); clearButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { clearButtonActionPerformed(evt); } }); clearButton.setBounds(120, 17, 90, 20); calculateDesktopPane.add(clearButton, javax.swing.JLayeredPane.DEFAULT_LAYER); paramButton.setFont(new java.awt.Font("Dialog", 1, 11)); paramButton.setText("Set Parameters..."); paramButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { paramButtonActionPerformed(evt); } }); paramButton.setBounds(7, 42, 130, 20); calculateDesktopPane.add(paramButton, javax.swing.JLayeredPane.DEFAULT_LAYER); calculateDesktopPane.setBounds(7, 377, 220, 70); desktopPane.add(calculateDesktopPane, javax.swing.JLayeredPane.DEFAULT_LAYER); zommDesktopPane.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)), "Zoom plot area")); zoomInButton.setFont(new java.awt.Font("Dialog", 1, 14)); zoomInButton.setText("+"); zoomInButton.setEnabled(false); zoomInButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { zoomInButtonActionPerformed(evt); } }); zoomInButton.setBounds(120, 17, 90, 20); zommDesktopPane.add(zoomInButton, javax.swing.JLayeredPane.DEFAULT_LAYER); zoomOutButton.setFont(new java.awt.Font("Dialog", 1, 14)); zoomOutButton.setText("-"); zoomOutButton.setEnabled(false); zoomOutButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { zoomOutButtonActionPerformed(evt); } }); zoomOutButton.setBounds(7, 17, 90, 20); zommDesktopPane.add(zoomOutButton, javax.swing.JLayeredPane.DEFAULT_LAYER); zommDesktopPane.setBounds(7, 447, 220, 45); desktopPane.add(zommDesktopPane, javax.swing.JLayeredPane.DEFAULT_LAYER); ecgWindow.getContentPane().add(desktopPane, java.awt.BorderLayout.CENTER); getContentPane().add(ecgWindow, java.awt.BorderLayout.CENTER); }//GEN-END:initComponents private void paramHelpButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_paramHelpButtonActionPerformed helpEditorPane.setContentType("text/html"); helpEditorPane.setText( " " + ""+ "" + " " + " " + " " + " " + " "+ " " + " " + " " + " " + "
ECGSYN " + " PARAMETER DOCUMENTATION
GENERAL " + " INTERFACE
" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
 Approximate number of heart beats:
" + " fjaklsdfjasldjasdjfgfagsdgfasdgfywerwaegsdgfwefasjkgiawegasfkgiawefaklsdgfaiwegfklasegfaiwegaklgawiegfafwgegfauiwegfkasdgfiawegfawiegfasdklgfialweugfasefiuawgefilugfawileugfawilegfaweilgfawilegfasiduflskdgfailwuegfawileusdjklgfawilesdfk
 
ECG Sampling Frequency
" + "
definition
 
Internal Sampling Frequency
" + "
definition
 
Amplitude of additive uniform noise
" + "
definition
 
Heart rate mean
" + "
definition
 
Heart rate standard deviation
" + "
definition
 
Seed
" + "
definition
" + "
" + " "); helpDialog.show(); }//GEN-LAST:event_paramHelpButtonActionPerformed private void alertButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_alertButtonActionPerformed alert.hide(); }//GEN-LAST:event_alertButtonActionPerformed private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); paramDialog.hide(); plotZoom = plotZoom / plotZoomInc; ecgFrame.repaint(); desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_zoomInButtonActionPerformed private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); paramDialog.hide(); plotZoom = plotZoom * plotZoomInc; ecgFrame.repaint(); desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_zoomOutButtonActionPerformed private void startAnimateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startAnimateButtonActionPerformed paramDialog.hide(); // Disabling automatic plot readyToPlot = false; ecgFrame.repaint(); /* * Initialize ECG Animate variables */ ecgAnimateFlg = true; ecgAnimateNumRows = tableValuesModel.getRowCount(); ecgAnimateCurRow = 0; ecgAnimatePanelWidth = ecgFrame.getBounds().width; ecgAnimateInitialZero = 0; ecgAnimateLastPoint.setLocation(0, posOriginY - (int)(Double.valueOf(tableValues.getValueAt(0, 1).toString()).doubleValue() * frameAmplitude / amplitude)); /* Create Timer */ ecgAnimateTimer = new Timer(); /* Schedule the Animate Plotting Task */ ecgAnimateTimer.scheduleAtFixedRate(new ECGAnimate(), 0, ecgAnimateInterval); /* Set the Animate Buttons */ startECGAnimationSetControls(); }//GEN-LAST:event_startAnimateButtonActionPerformed private void saveParamDialogButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveParamDialogButtonActionPerformed saveParametersValues(); paramDialog.hide(); }//GEN-LAST:event_saveParamDialogButtonActionPerformed private void resetParamDialogButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetParamDialogButtonActionPerformed clearParameters(); }//GEN-LAST:event_resetParamDialogButtonActionPerformed private void closeParamDialogButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeParamDialogButtonActionPerformed paramDialog.hide(); }//GEN-LAST:event_closeParamDialogButtonActionPerformed private void paramButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_paramButtonActionPerformed paramDialog.show(); }//GEN-LAST:event_paramButtonActionPerformed private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed paramDialog.hide(); exportDialog.setBounds(80, 80,500,500); exportDialog.show(); }//GEN-LAST:event_exportButtonActionPerformed private void saveParametersValues(){ txtStatus.setText(null); checkParameters(); } private void clearDataTable(){ // Delete the DataTable tableValuesModel.setRowCount(0); } /** * Draw a string in the center of a given box. * Reduce the font size if necessary to fit. Can * fix the type size to a value passed as an argument. * The position of the string within the box passed * as LEFT, CENTER or RIGHT constant value. * Don't draw the strings if they do not fit. */ private int drawText( Graphics g, String msg, int xBox, int yBox, int boxWidth, int boxHeight, int fixedTypeSizeValue, int position){ boolean fixedTypeSize = false; int typeSize = 24; // Fixed to a particular type size. if(fixedTypeSizeValue > 0) { fixedTypeSize = true; typeSize = fixedTypeSizeValue; } int typeSizeMin = 8; int x=xBox,y=yBox; do { // Create the font and pass it to the Graphics context g.setFont(new Font("Monospaced",Font.PLAIN,typeSize)); // Get measures needed to center the message FontMetrics fm = g.getFontMetrics(); // How many pixels wide is the string int msgWidth = fm.stringWidth(msg); // How tall is the text? int msgHeight = fm.getHeight(); // See if the text will fit in the allotted // vertical limits if( msgHeight < boxHeight && msgWidth < boxWidth) { y = yBox + boxHeight/2 +(msgHeight/2); if( position == CENTER) x = xBox + boxWidth/2 - (msgWidth/2); else if(position == RIGHT) x = xBox + boxWidth - msgWidth; else x = xBox; break; } // If fixedTypeSize and wouldn't fit, don't draw. if( fixedTypeSize) return -1; // Try smaller type typeSize -= 2; } while (typeSize >= typeSizeMin); // Don't display the numbers if they did not fit if( typeSize < typeSizeMin) return -1; // Otherwise, draw and return positive signal. g.drawString(msg,x,y); // ecgFrame.revalidate(); // ecgFrame.repaint(); return typeSize; } /* * ReInit the Button Parameters' values */ private void clearParameters(){ /* General Intergace parameters */ txtN.setText("256"); N = 256; txtSfecg.setText("256"); sfecg = 256; txtSf.setText("512"); sf = 512; txtAnoise.setText("0.1"); Anoise = 0.1; txtHrmean.setText("60.0"); hrmean = 60.0; txtHrstd.setText("1.0"); hrstd = 1.0; txtSeed.setText("1"); seed = 1; txtAmplitude.setText("1.4"); amplitude = 1.4; /* Spectral Characteristics parameters */ txtFlo.setText("0.1"); flo = 0.1; txtFhi.setText("0.25"); fhi = 0.25; txtFlostd.setText("0.01"); flostd = 0.01; txtFhistd.setText("0.01"); fhistd = 0.01; txtLfhfratio.setText("0.5"); lfhfratio = 0.5; /* * ECG morphology: Order of extrema: [P Q R S T] */ theta[1]= -60.0; theta[2]= -15.0; theta[3]= 0.0; theta[4]= 15.0; theta[5]= 90.0; a[1]= 1.2; a[2]= -5.0; a[3]= 30.0; a[4]= -7.5; a[5]= 0.75; b[1]= 0.25; b[2]= 0.1; b[3]= 0.1; b[4]= 0.1; b[5]= 0.4; //data tables tiTable.getModel().setValueAt(new Double(theta[1]), 0, 0); tiTable.getModel().setValueAt(new Double(theta[2]), 1, 0); tiTable.getModel().setValueAt(new Double(theta[3]), 2, 0); tiTable.getModel().setValueAt(new Double(theta[4]), 3, 0); tiTable.getModel().setValueAt(new Double(theta[5]), 4, 0); aiTable.getModel().setValueAt(new Double(a[1]), 0, 0); aiTable.getModel().setValueAt(new Double(a[2]), 1, 0); aiTable.getModel().setValueAt(new Double(a[3]), 2, 0); aiTable.getModel().setValueAt(new Double(a[4]), 3, 0); aiTable.getModel().setValueAt(new Double(a[5]), 4, 0); biTable.getModel().setValueAt(new Double(b[1]), 0, 0); biTable.getModel().setValueAt(new Double(b[2]), 1, 0); biTable.getModel().setValueAt(new Double(b[3]), 2, 0); biTable.getModel().setValueAt(new Double(b[4]), 3, 0); biTable.getModel().setValueAt(new Double(b[5]), 4, 0); /* * ECG Animate parameters */ // convert into miliseconds interval ecgAnimateInterval = (long)(1000/(sfecg)); } private void resetECG(){ ecgGenerated = false; clearParameters(); resetPlotArea(); resetButtons(); resetStatusBar(); } /* * Set the appropiate state of the controls for start the ECG Animation */ private void startECGAnimationSetControls(){ stopAnimateButton.setEnabled(true); //exportButton.setEnabled(true); clearButton.setEnabled(false); generateButton.setEnabled(false); paramButton.setEnabled(false); zoomInButton.setEnabled(false); zoomOutButton.setEnabled(false); startAnimateButton.setEnabled(false); } /* * Set the appropiate state of the controls for stop the ECG Animation */ private void stopECGAnimationSetControls(){ startAnimateButton.setEnabled(true); clearButton.setEnabled(true); generateButton.setEnabled(true); paramButton.setEnabled(true); zoomInButton.setEnabled(true); zoomOutButton.setEnabled(true); stopAnimateButton.setEnabled(false); } /* * Enable the buttons after generating the ecg Data. */ private void enableButtons(){ startAnimateButton.setEnabled(true); exportButton.setEnabled(true); clearButton.setEnabled(true); zoomInButton.setEnabled(true); zoomOutButton.setEnabled(true); } private void resetButtons(){ stopAnimateButton.setEnabled(false); startAnimateButton.setEnabled(false); exportButton.setEnabled(false); clearButton.setEnabled(false); zoomInButton.setEnabled(false); zoomOutButton.setEnabled(false); } private void resetPlotArea(){ lblMaxAmplitude.setText("1.4"); lblMinAmplitude.setText("-1.4"); readyToPlot = false; plotScrollBarValue = 0; } private void resetStatusBar(){ txtStatus.setText(null); txtStatus.append("**********************************************************\n"); txtStatus.append("Change desired ECG Parameters\n"); txtStatus.append("and then click 'Generate' button to generate and plot data\n"); txtStatus.append("**********************************************************"); } private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); paramDialog.hide(); // Delete the DataTable clearDataTable(); resetECG(); ecgFrame.repaint(); desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_clearButtonActionPerformed private void stopAnimateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopAnimateButtonActionPerformed paramDialog.hide(); /* Stop the Animate Plotting Task */ ecgAnimateTimer.cancel(); ecgAnimateFlg =false; /* Enable automatic plot */ readyToPlot = true; /* Repaint Plot Area */ ecgFrame.repaint(); /* Set the Animate Buttons */ stopECGAnimationSetControls(); }//GEN-LAST:event_stopAnimateButtonActionPerformed private boolean checkParameters(){ txtStatus.append("Starting to check ECG parameters entered...\n"); boolean RetValue = true; //ECG Sampling frequency flag boolean sfecg_flg = true; //Internal Sampling frequency flag boolean sf_flg = true; /* General Intergace parameters */ try { N = Integer.valueOf(txtN.getText()).intValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Approximate number of heart beats' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { sfecg = Integer.valueOf(txtSfecg.getText()).intValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'ECG Sampling Frequency' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); sfecg_flg = false; RetValue = false; } if(sfecg_flg){ try { sf = Integer.valueOf(txtSf.getText()).intValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Internal Sampling Frequency' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); sf_flg = false; RetValue = false; } } // Check the Internal frequency respect to ECG frequency if(sfecg_flg && sf_flg){ if(((int)Math.IEEEremainder(sf, sfecg)) != 0){ txtStatus.append("Internal sampling frequency must be an integer multiple of the\n"); txtStatus.append("ECG sampling frequency!, that currently is = " + sfecg + " Hertz\n"); RetValue = false; } } try { Anoise = Double.valueOf(txtAnoise.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Amplitude of additive uniform noise' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { hrmean = Double.valueOf(txtHrmean.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Heart rate mean' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { hrstd = Double.valueOf(txtHrstd.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Heart rate standard deviation' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { seed = Integer.valueOf(txtSeed.getText()).intValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'seed' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { amplitude = Double.valueOf(txtAmplitude.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Plot Area Amplitude' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } /* Spectral Characteristics parameters */ try { flo = Double.valueOf(txtFlo.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Low frequency' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { fhi = Double.valueOf(txtFhi.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'High frequency' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { flostd = Double.valueOf(txtFlostd.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'Low frequency standard deviation' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { fhistd = Double.valueOf(txtFhistd.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'High frequency standard deviation' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { lfhfratio = Double.valueOf(txtLfhfratio.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'LF/HF ratio' entered, please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } /* * ECG morphology: Order of extrema: [P Q R S T] */ // theta try { theta[1] = Double.valueOf(tiTable.getValueAt(0,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'theta' value entered (position 1), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { theta[2] = Double.valueOf(tiTable.getValueAt(1,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'theta' value entered (position 2), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { theta[3] = Double.valueOf(tiTable.getValueAt(2,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'theta' value entered (position 3), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { theta[4] = Double.valueOf(tiTable.getValueAt(3,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'theta' value entered (position 4), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { theta[5] = Double.valueOf(tiTable.getValueAt(4,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'theta' value entered (position 5), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } // a try { a[1] = Double.valueOf(aiTable.getValueAt(0,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'a' value entered (position 1), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { a[2] = Double.valueOf(aiTable.getValueAt(1,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'a' value entered (position 2), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { a[3] = Double.valueOf(aiTable.getValueAt(2,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'a' value entered (position 3), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { a[4] = Double.valueOf(aiTable.getValueAt(3,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'a' value entered (position 4), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { a[5] = Double.valueOf(aiTable.getValueAt(4,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'a' value entered (position 5), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } // b try { b[1] = Double.valueOf(biTable.getValueAt(0,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'b' value entered (position 1), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { b[2] = Double.valueOf(biTable.getValueAt(1,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'b' value entered (position 2), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { b[3] = Double.valueOf(biTable.getValueAt(2,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'b' value entered (position 3), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { b[4] = Double.valueOf(biTable.getValueAt(3,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'b' value entered (position 4), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } try { b[5] = Double.valueOf(biTable.getValueAt(4,0).toString()).doubleValue(); } catch(java.lang.NumberFormatException e){ txtStatus.append("Incorrect 'b' value entered (position 5), please correct it!\n"); txtStatus.append("Exception Error : " + e + "\n"); RetValue = false; } /* * ECG Animate parameters */ // convert into miliseconds interval ecgAnimateInterval = (long)(1000/(sfecg)); if(RetValue){ txtStatus.append("All parameters are valid!.\n"); }else{ txtStatus.append("There were errors in some parameters!.\n"); } txtStatus.append("Finished checking ECG parameters.\n\n"); return(RetValue); } /************************* * THE ECG FUNCTION **************************/ boolean ecgFunction(){ boolean RetValue; txtStatus.append("Starting to generate ECG table data....\n"); ecgCalc Ecg = new ecgCalc(); RetValue = Ecg.dorun(); txtStatus.append("Finished generating ECG table data.\n\n"); return(RetValue); } private void generateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_generateButtonActionPerformed desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); paramDialog.hide(); /* * Clear Status text. */ txtStatus.setText(null); txtStatus.append("************************************************************\n"); txtStatus.append("ECGSYN:\nA program for generating a realistic synthetic ECG\n\n"); txtStatus.append("Copyright (c) 2003 by Patrick McSharry & Gari Clifford.\n"); txtStatus.append("All rights reserved.\n"); txtStatus.append("See IEEE Transactions On Biomedical Engineering, 50(3),\n289-294, March 2003.\n\n"); txtStatus.append("Contact:\nP. McSharry (patrick@mcsharry.net)\nG. Clifford (gari@mit.edu)\n"); txtStatus.append("************************************************************\n\n"); txtStatus.append("ECG process started.\n\n"); txtStatus.append("Starting to clear table data and widgets values....\n"); /* * Set the Amplitude labels */ lblMaxAmplitude.setText(txtAmplitude.getText()); lblMinAmplitude.setText("-" + txtAmplitude.getText()); /* * Re init the plot state. * Disable repaint for the moment, until we finish the FFT function. */ readyToPlot = false; plotScrollBarValue = 0; plotScrollBar.setMaximum(0); /* Delete any data on the Data Table. */ clearDataTable(); txtStatus.append("Finished clearing table data and widgets values.\n\n"); /* * Call the ECG funtion to calculate the data into the Data Table. */ if(ecgFunction()){ txtStatus.append("Starting to plot ECG table data....\n"); /* * if the # Data Table rows is less than the ecgFrame width, we do not * need the scrollbar */ int rows = tableValuesModel.getRowCount(); if(rows > ecgFrame.getBounds().width){ plotScrollBar.setMaximum(rows - ecgFrame.getBounds().width - 1); } /* * Only plot if there's data in the table. */ if(rows > 0){ readyToPlot = true; ecgGenerated = true; enableButtons(); }else{ txtStatus.append("No data to plot!.\n"); } ecgFrame.repaint(); txtStatus.append("Finished plotting ECG table data.\n\n"); } txtStatus.append("Finsihed ECG process.\n"); txtStatus.append("************************************************************\n"); desktopPane.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_generateButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane ExtremaLabelScrollPane; private javax.swing.JTable ExtremaLabelTable; private javax.swing.JScrollPane TableScrollPane; private javax.swing.JScrollPane aiScrollPane; private javax.swing.JTable aiTable; private javax.swing.JDialog alert; private javax.swing.JButton alertButton; private javax.swing.JDesktopPane alertDesktopPane; private javax.swing.JTextArea alertText; private javax.swing.JLabel alertTitle; private javax.swing.JDesktopPane animateDesktopPane; private javax.swing.JScrollPane biScrollPane; private javax.swing.JTable biTable; private javax.swing.JDesktopPane calculateDesktopPane; private javax.swing.JButton clearButton; private javax.swing.JButton closeParamDialogButton; private javax.swing.JDesktopPane desktopPane; private javax.swing.JScrollPane ecgPlotArea; private javax.swing.JInternalFrame ecgWindow; private javax.swing.JButton exportButton; private javax.swing.JDialog exportDialog; private javax.swing.JPanel extremaPanel; private javax.swing.JPanel generalInterfacePanel; private javax.swing.JButton generateButton; private javax.swing.JDialog helpDialog; private javax.swing.JEditorPane helpEditorPane; private javax.swing.JInternalFrame helpInternalFrame; private javax.swing.JScrollPane helpScrollPane; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; private javax.swing.JLabel lblAmplitude; private javax.swing.JLabel lblAnoise; private javax.swing.JLabel lblFhi; private javax.swing.JLabel lblFhistd; private javax.swing.JLabel lblFlo; private javax.swing.JLabel lblFlostd; private javax.swing.JLabel lblGeneralTitle; private javax.swing.JLabel lblHrmean; private javax.swing.JLabel lblHrstd; private javax.swing.JLabel lblLfhfratio; private javax.swing.JLabel lblMaxAmplitude; private javax.swing.JLabel lblMinAmplitude; private javax.swing.JLabel lblMorphologyTitle; private javax.swing.JLabel lblN; private javax.swing.JLabel lblOrigin; private javax.swing.JLabel lblSeed; private javax.swing.JLabel lblSf; private javax.swing.JLabel lblSfecg; private javax.swing.JLabel lblSpectralTitle; private javax.swing.JLabel lblXAxis; private javax.swing.JButton paramButton; private javax.swing.JDesktopPane paramDesktopPane; private javax.swing.JDialog paramDialog; private javax.swing.JButton paramHelpButton; private javax.swing.JTabbedPane paramTabbedPane; private javax.swing.JScrollBar plotScrollBar; private javax.swing.JButton resetParamDialogButton; private javax.swing.JButton saveParamDialogButton; private javax.swing.JPanel spectralCharacteristicsPanel; private javax.swing.JButton startAnimateButton; private javax.swing.JScrollPane statusScrollPane; private javax.swing.JButton stopAnimateButton; private javax.swing.JTable tableValues; private javax.swing.JScrollPane tiScrollPane; private javax.swing.JTable tiTable; private javax.swing.JTextField txtAmplitude; private javax.swing.JTextField txtAnoise; private javax.swing.JTextField txtFhi; private javax.swing.JTextField txtFhistd; private javax.swing.JTextField txtFlo; private javax.swing.JTextField txtFlostd; private javax.swing.JTextField txtHrmean; private javax.swing.JTextField txtHrstd; private javax.swing.JTextField txtLfhfratio; private javax.swing.JTextField txtN; private javax.swing.JTextField txtSeed; private javax.swing.JTextField txtSf; private javax.swing.JTextField txtSfecg; private javax.swing.JTextArea txtStatus; private javax.swing.JDesktopPane zommDesktopPane; private javax.swing.JButton zoomInButton; private javax.swing.JButton zoomOutButton; // End of variables declaration//GEN-END:variables private javax.swing.table.DefaultTableModel tableValuesModel; private ecgPanel ecgFrame; /* * This class is the AdjustmentListener for the * scroll bar. So the events come here when the * scroll bar is moved. */ public void adjustmentValueChanged(AdjustmentEvent evt){ plotScrollBarValue = plotScrollBar.getValue(); ecgFrame.repaint(); } class ecgPanel extends javax.swing.JPanel{ public void paintComponent(Graphics g){ // First call the paintComponent of the // superclass, in this case JPanel. super.paintComponent(g); /* Draw the plot frame. */ g.setColor(frameLineColor); g.drawLine(0, posFrameY, ecgFrame.getBounds().width, posFrameY); g.drawLine(0, posOriginY, this.getBounds().width, posOriginY); g.drawLine(0, horzScaleY, this.getBounds().width, horzScaleY); if(readyToPlot){ int rows = tableValuesModel.getRowCount(); int x, y, i; int plotLimit; int initialZero; int curSecond, lastSecond; String strValue; /* * Set the first point to the current Table row */ initialZero = (int)(Double.valueOf(tableValues.getValueAt(plotScrollBarValue, 0).toString()).doubleValue() / plotZoom); lastSecond = (int)(Double.valueOf(tableValues.getValueAt(plotScrollBarValue, 0).toString()).doubleValue()); x = 0; y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(plotScrollBarValue, 1).toString()).doubleValue() * frameAmplitude / amplitude); Point lastPoint = new java.awt.Point(x, y); i= plotScrollBarValue; while((x <= this.getBounds().width)&& (i <=rows)){ curSecond = (int)(Double.valueOf(tableValues.getValueAt(i, 0).toString()).doubleValue()); if(curSecond > lastSecond){ lastSecond = curSecond; // Convert the x value to a string strValue = FormatNumber.toString(Double.valueOf(tableValues.getValueAt(i, 0).toString()).doubleValue(), upLimit, loLimit, 2); /* * Plot the X axes number values (the Time). */ g.setColor(axesNumColor); drawText(g, strValue, x, horzScaleY, horzScaleWidth, horzScaleHeight, fScaleNumSize,LEFT); g.setColor(frameInsideLineColor); g.drawLine(x, posFrameY, x, horzScaleY + 5); } /* * Plot a line between the las point and the current point. * This to create a illusion to connect the two points. */ g.setColor(ecgPlotColor); g.drawLine(lastPoint.x, lastPoint.y, x, y); /* * Set the current point to be the last, and * get a new point to plot in the following loop. */ lastPoint.setLocation(x, y); i+= 1; x = (int)(Double.valueOf(tableValues.getValueAt(i, 0).toString()).doubleValue() / plotZoom) - initialZero; y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(i, 1).toString()).doubleValue() * frameAmplitude / amplitude); } } } } class ecgCalc{ /* C defines */ private final double PI = 2.0*Math.asin(1.0); private final int NR_END = 1; private final int IA = 16807; private final long IM = 2147483647; private final double AM = (1.0/IM); private final long IQ = 127773; private final int IR = 2836; private final int NTAB = 32; private final double NDIV = (1+(IM-1)/NTAB); private final double EPS = 1.2e-7; private final double RNMX = (1.0-EPS); /***************************************************************************** * DEFINE PARAMETERS AS GLOBAL VARIABLES * *****************************************************************************/ private String outfile ="ecgsyn.dat"; // Order of extrema: [P Q R S T] private double[] ti = new double[6]; /* ti converted in radians */ private double[] ai = new double[6]; /* new calculated a */ private double[] bi = new double[6]; /* new calculated b */ private int Necg = 0; /* Number of ECG outputs */ private int mstate = 3; /* System state space dimension */ private double xinitial = 1.0; /* Initial x co-ordinate value */ private double yinitial = 0.0; /* Initial y co-ordinate value */ private double zinitial = 0.04; /* Initial z co-ordinate value */ private long rseed; private double h; private double[] rr, rrpc; /* * Variables for static function rand() */ private long iy; private long[] iv; public ecgCalc(){ /* variables for static function ranq() */ iy=0; iv = new long[NTAB]; } /*--------------------------------------------------------------------------*/ /* UNIFORM DEVIATES */ /*--------------------------------------------------------------------------*/ private double rand(){ int j; long k; double temp; boolean flg; if(iy == 0) flg = false; else flg = true; if((rseed <= 0) || !flg){ if (-(rseed) < 1) rseed = 1; else rseed = -rseed; for (j=NTAB+7; j>=0; j--) { k=(rseed)/IQ; rseed=IA*(rseed-k*IQ)-IR*k; if (rseed < 0) rseed += IM; if (j < NTAB) iv[j] = rseed; } iy=iv[0]; } k=(rseed)/IQ; rseed=IA*(rseed-k*IQ)-IR*k; if (rseed< 0) rseed += IM; j = (int)(iy/NDIV); iy=iv[j]; iv[j] = rseed; if ((temp=AM*iy) > RNMX) return RNMX; else return temp; } /* * FFT */ private void ifft(double[] data, long nn, int isign){ long n, mmax, m, istep, i, j; double wtemp,wr,wpr,wpi,wi,theta; double tempr,tempi; double swap; n=nn << 1; j=1; for (i=1; i< n; i+=2) { if (j > i) { //SWAP(data[j],data[i]); swap = data[(int) j]; data[(int)j] = data[(int)i]; data[(int)i] = swap; //SWAP(data[j+1],data[i+1]); swap = data[(int)j+1]; data[(int)j+1] = data[(int)i+1]; data[(int)i+1] = swap; } m=n >> 1; while (m >= 2 && j > m) { j -= m; m >>= 1; } j += m; } mmax=2; while (n > mmax) { istep=mmax << 1; theta=isign*(6.28318530717959/mmax); wtemp=Math.sin(0.5*theta); wpr = -2.0*wtemp*wtemp; wpi=Math.sin(theta); wr=1.0; wi=0.0; for (m=1; m (i-d) ? 1 : (i-d)); //MAX(1,i-d); j2 = (n < (i+d) ? n : (i+d)); //MIN(n,i+d); jmax = j1; zmax = z[j1]; for(j=j1+1;j<=j2;j++){ if(z[j] > zmax){ jmax = j; zmax = z[j]; } } if(jmax != i){ ipeak[jmax] = ipeak[i]; ipeak[i] = 0; } } else if( ipeak[i]==2 || ipeak[i]==4 ){ j1 = (1 > (i-d) ? 1 : (i-d));//MAX(1,i-d); j2 = (n < (i+d) ? n : (i+d)); //MIN(n,i+d); jmin = j1; zmin = z[j1]; for(j=j1+1;j<=j2;j++){ if(z[j] < zmin){ jmin = j; zmin = z[j]; } } if(jmin != i){ ipeak[jmin] = ipeak[i]; ipeak[i] = 0; } } } } /* * DORUN PART OF PROGRAM */ public boolean dorun(){ boolean RetValue = true; int i, j, k, Nrr, Nt, Nts; int q; double[] x; double tstep, tecg, rrmean, hrfact, hrfact2; double qd; double[] xt, yt, zt, xts, yts, zts; double timev, zmin, zmax, zrange; double[] ipeak; // perform some checks on input values q = (int) Math.rint(sf/sfecg); qd = (double)sf/(double)sfecg; /* convert angles from degrees to radians and copy a vector to ai*/ for(i=1; i <= 5; i++){ ti[i] = theta[i] * PI/180.0; ai[i] = a[i]; } /* adjust extrema parameters for mean heart rate */ hrfact = Math.sqrt(hrmean/60); hrfact2 = Math.sqrt(hrfact); for(i=1; i <= 5; i++) bi[i] = b[i] * hrfact; ti[1] *= hrfact2; ti[2] *= hrfact; ti[3] *= 1.0; ti[4] *= hrfact; ti[5] *= 1.0; /* declare state vector */ //x=dvector(1,mstate); x= new double[4]; txtStatus.append("Approximate number of heart beats: " + N +"\n"); txtStatus.append("ECG sampling frequency: " + sfecg + " Hertz\n"); txtStatus.append("Internal sampling frequency: " + sf + " Hertz\n"); txtStatus.append("Amplitude of additive uniformly distributed noise: " + Anoise + " mV\n"); txtStatus.append("Heart rate mean: " + hrmean + " beats per minute\n"); txtStatus.append("Heart rate std: " + hrstd + " beats per minute\n"); txtStatus.append("Low frequency: " + flo + " Hertz\n"); txtStatus.append("High frequency std: " + fhistd + " Hertz\n"); txtStatus.append("Low frequency std: " + flostd + " Hertz\n"); txtStatus.append("High frequency: " + fhi + " Hertz\n"); txtStatus.append("LF/HF ratio: " + lfhfratio + "\n"); txtStatus.append("time step milliseconds: " + ecgAnimateInterval + "\n\n"); txtStatus.append("Order of Extrema:\n"); txtStatus.append(" theta(radians)\n"); txtStatus.append("P: ["+ ti[1] + "\t]\n"); txtStatus.append("Q: ["+ ti[2] + "\t]\n"); txtStatus.append("R: ["+ ti[3] + "\t]\n"); txtStatus.append("S: ["+ ti[4] + "\t]\n"); txtStatus.append("T: ["+ ti[5] + "\t]\n\n"); txtStatus.append(" a(calculated)\n"); txtStatus.append("P: ["+ ai[1] + "\t]\n"); txtStatus.append("Q: ["+ ai[2] + "\t]\n"); txtStatus.append("R: ["+ ai[3] + "\t]\n"); txtStatus.append("S: ["+ ai[4] + "\t]\n"); txtStatus.append("T: ["+ ai[5] + "\t]\n\n"); txtStatus.append(" b(calculated)\n"); txtStatus.append("P: ["+ bi[1] + "\t]\n"); txtStatus.append("Q: ["+ bi[2] + "\t]\n"); txtStatus.append("R: ["+ bi[3] + "\t]\n"); txtStatus.append("S: ["+ bi[4] + "\t]\n"); txtStatus.append("T: ["+ bi[5] + "\t]\n\n"); /* Initialise the vector */ x[1] = xinitial; x[2] = yinitial; x[3] = zinitial; /* initialise seed */ rseed = -seed; /* calculate time scales */ h = 1.0/(double)sf; tstep = 1.0/(double)sfecg; /* calculate length of RR time series */ rrmean = (60.0/hrmean); Nrr=(int)Math.pow(2.0, Math.ceil(Math.log(N*rrmean*sf)/Math.log(2.0))); txtStatus.append("Using " + Nrr + " = 2^ "+ (int)(Math.log(1.0*Nrr)/Math.log(2.0)) + " samples for calculating RR intervals\n"); /* create rrprocess with required spectrum */ rr = new double[Nrr + 1]; rrprocess(rr, flo, fhi, flostd, fhistd, lfhfratio, hrmean, hrstd, sf, Nrr); /* create piecewise constant rr */ rrpc = new double[(2*Nrr) + 1]; tecg = 0.0; i = 1; j = 1; while(i <= Nrr){ tecg += rr[j]; j = (int) Math.rint(tecg/h); for(k=i; k<=j; k++) rrpc[k] = rr[i]; i = j+1; } Nt = j; /* integrate dynamical system using fourth order Runge-Kutta*/ xt = new double[Nt + 1]; yt = new double[Nt + 1]; zt = new double[Nt + 1]; timev = 0.0; for(i=1; i<=Nt; i++){ xt[i] = x[1]; yt[i] = x[2]; zt[i] = x[3]; Rk4(x, mstate, timev, h, x); timev += h; } /* downsample to ECG sampling frequency */ xts = new double[Nt + 1]; yts = new double[Nt + 1]; zts = new double[Nt + 1]; j=0; for(i=1; i<=Nt; i+=q){ j++; xts[j] = xt[i]; yts[j] = yt[i]; zts[j] = zt[i]; } Nts = j; /* do peak detection using angle */ ipeak = new double[Nts + 1]; detectpeaks(ipeak, xts, yts, zts, Nts); /* scale signal to lie between -0.4 and 1.2 mV */ zmin = zts[1]; zmax = zts[1]; for(i=2; i<=Nts; i++){ if(zts[i] < zmin) zmin = zts[i]; else if(zts[i] > zmax) zmax = zts[i]; } zrange = zmax-zmin; for(i=1; i<=Nts; i++) zts[i] = (zts[i]-zmin)*(1.6)/zrange - 0.4; /* include additive uniformly distributed measurement noise */ for(i=1; i<=Nts; i++) zts[i] += Anoise*(2.0*rand() - 1.0); /* * insert into the ECG data table */ txtStatus.append("Inserting rows...\n"); for(i=1;i<=Nts;i++){ //fprintf(fp,"%f %f %d\n",(i-1)*tstep,zts[i],(int)ipeak[i]); Vector nuevoRow = new Vector(3); nuevoRow.addElement(new String(Double.toString((i-1)*tstep))); nuevoRow.addElement(new String(Double.toString(zts[i]))); nuevoRow.addElement(new String(Integer.toString((int)ipeak[i]))); tableValuesModel.addRow(nuevoRow); } txtStatus.append("Finished inserting (" + i + ") rows.\n"); //RetValue = false; return(RetValue); } } /* * Class to plot the ECG animation */ class ECGAnimate extends TimerTask{ int x = 0; int y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 1).toString()).doubleValue() * frameAmplitude / amplitude); int curSecond = 0; int lastSecond = 0; Graphics ga = ecgFrame.getGraphics(); public void run(){ curSecond = (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 0).toString()).doubleValue()); if(curSecond > lastSecond){ lastSecond = curSecond; /* * Plot the X axes number values (the Time). */ ga.setColor(axesNumColor); drawText(ga, FormatNumber.toString(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 0).toString()).doubleValue(), upLimit, loLimit, 2), x, horzScaleY, horzScaleWidth, horzScaleHeight, fScaleNumSize,LEFT); ga.setColor(frameInsideLineColor); ga.drawLine(x, posFrameY, x, horzScaleY + 5); } ga.setColor(ecgPlotColor); ga.drawLine(ecgAnimateLastPoint.x, ecgAnimateLastPoint.y, x, y); ecgAnimateCurRow += 1; if(ecgAnimateCurRow >= ecgAnimateNumRows){ /* * If we reach the end of the Data Table, loop again entire table. */ ecgFrame.repaint(); ecgAnimateCurRow = 0; ecgAnimateInitialZero = 0; x = 0; y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 1).toString()).doubleValue() * frameAmplitude / amplitude); ecgAnimateLastPoint.setLocation(x, y); curSecond = 0; lastSecond = 0; } else if(x > ecgAnimatePanelWidth){ /* * If we not reached the end of the Data Table, but we reach to the limit of * the Plot Area. so reset the X coordinate to begin again. */ ecgFrame.repaint(); x = 0; y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 1).toString()).doubleValue() * frameAmplitude / amplitude); ecgAnimateInitialZero = (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 0).toString()).doubleValue() / plotZoom); ecgAnimateLastPoint.setLocation(x, y); //curSecond = 0; //lastSecond = 0; } else{ ecgAnimateLastPoint.setLocation(x, y); x = (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 0).toString()).doubleValue() / plotZoom) - ecgAnimateInitialZero; y = posOriginY - (int)(Double.valueOf(tableValues.getValueAt(ecgAnimateCurRow, 1).toString()).doubleValue() * frameAmplitude / amplitude); } } } /* * class for verifying that the value of JtextField is a double number */ class doubleVerifier extends InputVerifier{ public boolean verify(JComponent input) { JTextField textF = (JTextField) input; double dNumber; boolean RetValue = true; try { dNumber = Double.valueOf(textF.getText()).doubleValue(); } catch(java.lang.NumberFormatException e){ getToolkit().beep(); alert.setTitle("Error!!!"); alertText.setText("You have to enter a double number, please retry!!!"); alert.show(); RetValue = false; } return(RetValue); } } /* * class for verifying that the value of JtextField is an integer number */ class integerVerifier extends InputVerifier{ public boolean verify(JComponent input) { JTextField textF = (JTextField) input; int dNumber; boolean RetValue = true; try { dNumber = Integer.valueOf(textF.getText()).intValue(); } catch(java.lang.NumberFormatException e){ getToolkit().beep(); alert.setTitle("Error!!!"); alertText.setText("You have to enter an integer number, please retry!!!"); alert.show(); RetValue = false; } return(RetValue); } } /* * class for verifying the value of the ECG Sampling frequency */ class sfecgVerifier extends InputVerifier{ public boolean verify(JComponent input) { JTextField textF = (JTextField) input; int dNumber; boolean RetValue = true; try { dNumber = Integer.valueOf(textF.getText()).intValue(); txtSf.setText(Integer.toString(dNumber)); } catch(java.lang.NumberFormatException e){ getToolkit().beep(); alert.setTitle("Error!!!"); alertText.setText("You have to enter an integer number, please retry!!!"); alert.show(); RetValue = false; } return(RetValue); } } /* * class for verifying the value of the Internal Sampling frequency */ class sfVerifier extends InputVerifier{ public boolean verify(JComponent input) { JTextField textF = (JTextField) input; int dNumber; boolean RetValue = true; try { dNumber = Integer.valueOf(textF.getText()).intValue(); int sfecgTemp; sfecgTemp = Integer.valueOf(txtSfecg.getText()).intValue(); if(((int)Math.IEEEremainder(dNumber, sfecgTemp)) != 0){ getToolkit().beep(); alert.setTitle("Error!!!"); alertText.setText("Internal sampling frequency must be an integer multiple of the ECG sampling frequency, please retry!"); alert.show(); RetValue = false; } } catch(java.lang.NumberFormatException e){ getToolkit().beep(); alert.setTitle("Error!!!"); alertText.setText("You have to enter an integer number, please retry!!!"); alert.show(); RetValue = false; } return(RetValue); } } }