Dydx swap Is a practical guide to trading on dYdX

Dydx swap Is a way many searchers describe using dYdX to exchange crypto exposure through a swap-style trading flow. On dYdX, that may mean placing a simple market-style trade, opening or closing a perpetual position, or using a spot interface where available. The important point is that a Dydx swap is still a trade: price, liquidity, fees, funding, margin, wallet security, and jurisdiction rules all matter before any order is confirmed.

Dydx swap can sound like a one-click token exchange, but dYdX is best known as a decentralized exchange focused on advanced markets such as perpetual contracts. A user may see a familiar swap screen, choose a market, enter an amount, review the estimated execution, and submit the transaction or order. Behind that simple flow, the platform still depends on order books, market liquidity, collateral, risk parameters, and settlement rules that are different from a basic wallet-to-wallet token swap.

What is Dydx swap?

Dydx swap is not a single universal product name that always means the same thing in every dYdX interface. It is a practical phrase for trading through dYdX in a streamlined way. In many cases, the phrase points to a swap-style experience for perpetuals, where a trader can take long or short exposure to an asset without buying the underlying token. In other cases, it may refer to spot-style buying and selling where the interface supports it.

Dydx swap should be understood alongside the core dYdX concepts: decentralized exchange access, self-custody, collateral, order execution, and transparent market rules. A traditional spot swap is usually an exchange of one token for another. A perpetual swap is a derivative contract that tracks an asset price without an expiry date. That distinction matters because a Dydx swap involving perpetuals can include leverage, liquidation risk, and recurring funding payments.

For a new user, the cleanest mental model is this: Dydx swap is the front-end action, while the market structure underneath determines the real risk. If the trade is a spot trade, the main questions are price, slippage, fees, and settlement. If the trade is a perpetual trade, the user must also understand margin, funding rate, position size, and the possibility of forced liquidation during volatile moves.

How does Dydx swap work behind the screen?

Dydx swap begins when a user selects a market and enters the amount they want to trade. The interface typically estimates the execution price and may show fees, price impact, leverage, margin requirement, or other trade details. A market order is designed to execute quickly against available liquidity. A limit order waits for a chosen price. Even when the interface looks simple, the order is still being matched against a market with bids, asks, depth, and changing prices.

Dydx swap execution depends on liquidity. If a market has deep liquidity, a modest trade may fill close to the quoted price. If liquidity is thin, a larger trade can move through multiple price levels and create more slippage. This is why the estimated output or position entry price should be reviewed carefully before confirming. A Dydx swap is not guaranteed to execute at the first number a user sees when the market is moving.

The protocol and interface may also rely on specific collateral assets, commonly stablecoin margin for perpetual markets. This means a trader might deposit or bridge funds, then use that collateral to trade different markets. In practice, Dydx swap activity is less like swapping tokens inside a simple automated market maker and more like trading on a professional exchange with decentralized infrastructure and wallet-based access.

How is Dydx swap different from a regular token swap?

Dydx swap differs from a regular decentralized token swap because dYdX has historically centered on derivatives and order-book trading rather than only automated pool swaps. A common DeFi swap on an automated market maker routes through liquidity pools. The user sends one asset and receives another, with the price set by pool reserves and routing. A Dydx swap for a perpetual market instead opens or closes a contract position that reflects price exposure.

Dydx swap also changes what ownership means. In a simple spot swap, receiving ETH, SOL, or another token means the user now owns that token in a wallet or account environment. In a perpetual swap, the trader owns a position, not the underlying asset. The position can gain or lose value as the market moves, and it can be affected by funding rates and margin requirements. This makes risk management central to the experience.

Users comparing a Dydx swap with other DeFi flows should look at the trade objective. A token swap may suit someone who wants to hold an asset. A perpetual swap may suit someone seeking price exposure, hedging, or short exposure, but it is more complex. To understand the derivative side in more depth, readers can compare the mechanics with a broader guide to before placing any leveraged trade.

When do traders use Dydx swap?

Dydx swap is commonly used when a trader wants fast exposure to a market without navigating a full advanced trading panel. The simplified flow can be useful for opening a position, closing a position, changing market direction, or converting collateral into market exposure. Experienced users may still prefer advanced order types, but a swap-style screen can reduce friction for straightforward trades.

Dydx swap can also be part of a hedging workflow. A user holding spot crypto elsewhere might use a perpetual position to offset some downside risk. Another user might close exposure quickly during a volatile market. Some traders use dYdX because they want non-custodial access, transparent market rules, and a trading environment that does not require handing assets to a traditional centralized exchange.

Common Dydx swap use cases include:

These use cases are not recommendations. Dydx swap can be useful, but usefulness depends on the user's experience, eligibility, risk tolerance, and understanding of the exact market being traded.

How to get started with Dydx swap

Dydx swap usually starts with confirming that the user is on the official dYdX interface and that the feature is available in their location. This step is not cosmetic. Crypto phishing sites often imitate exchanges, and eligibility rules can vary by jurisdiction. A user should verify the domain, review the official terms, and avoid connecting a wallet to a page reached through a suspicious ad, message, or copied link.

Dydx swap then requires a funded wallet or account setup supported by the current dYdX flow. Depending on the version of the interface and the market, the user may need to deposit collateral, bridge assets, or approve a connection. The exact steps can change as dYdX develops, so the safest approach is to follow the official interface prompts while checking each permission and transaction before signing.

A careful Dydx swap workflow looks like this:

  1. Choose the intended market and confirm whether it is spot or perpetual.
  2. Enter a small trade size first if you are learning the interface.
  3. Review estimated price, fee, slippage, margin, and liquidation information.
  4. Confirm that the order type matches the goal, such as market or limit.
  5. Submit only after checking wallet prompts and final trade details.

After a Dydx swap executes, the work is not finished if the result is an open perpetual position. The user should monitor unrealized profit and loss, margin usage, funding, and liquidation price. A spot position may simply remain in the account or wallet, but a leveraged perpetual position needs active oversight.

Fees, funding, and price impact in Dydx swap

Dydx swap costs can include trading fees, spread, slippage, network or bridging costs, and funding payments for perpetual positions. Trading fees are usually the most visible cost, but they are not always the largest one. A fast market order in a thin market can have meaningful price impact. A leveraged position held over time can also be affected by funding, which transfers value between long and short sides depending on market conditions.

Dydx swap fee schedules and market parameters can change, so users should verify current details in the official interface before trading. The displayed fee tier, any promotional fee changes, and the relevant market rules are more reliable than a static article. This is especially important for active traders, because small cost differences can matter when entering and exiting frequently.

In practice, a Dydx swap should be reviewed as an all-in trade, not just a headline fee. The execution price, expected slippage, available depth, collateral impact, and exit plan all affect the result. If a trade uses leverage, the effective exposure is larger than the collateral posted, which means gains and losses can move faster than a spot token position of the same deposit size.

Dydx swap trading workflow on exchange

Is Dydx swap safe?

Dydx swap can be safer when a user follows strong security practices, but no crypto trading flow is risk-free. The main safety categories are platform risk, smart contract or protocol risk, market risk, wallet risk, and user error. A decentralized exchange reduces some custody risks because users interact through wallets and protocol infrastructure, but it does not remove trading losses, liquidation, phishing, or operational mistakes.

Dydx swap safety starts with the basics: use the official site, protect seed phrases, avoid blind signing, keep wallet software updated, and understand every approval. A user should be especially cautious about social media links, unsolicited support messages, fake airdrops, and copycat domains. The platform cannot protect a wallet if the user signs a malicious transaction or shares recovery credentials.

Market safety is a separate issue. Dydx swap trades can lose money even when the technology works exactly as designed. Perpetual contracts may liquidate if margin falls below maintenance requirements. Funding rates can reduce returns. Volatile assets can move sharply before a user has time to react. Anyone using leverage should understand that losses can happen quickly and should never rely on guaranteed outcomes.

Dydx swap compared with centralized exchanges and other DEXs

Dydx swap sits between two familiar trading worlds. Compared with a centralized exchange, dYdX emphasizes decentralized infrastructure and wallet-based access. Compared with a simple automated market maker, dYdX can feel closer to an advanced trading venue because it uses markets, order types, margin, and derivatives. That mix is appealing to some traders and too complex for others.

A centralized exchange may offer fiat ramps, customer support, and a broad set of account services, but it also requires users to trust the exchange with custody and account controls. A Dydx swap can reduce reliance on a custodial intermediary, yet it shifts more responsibility to the user. Wallet security, transaction review, collateral management, and eligibility checks become personal responsibilities rather than back-office tasks handled by a broker-like platform.

Other decentralized exchanges may be better for simple token-to-token swaps, especially when the goal is to acquire and hold an asset across many chains. Dydx swap may be more relevant when the goal is derivatives trading, short exposure, or professional-style crypto market access. Readers comparing exchange styles may also want to review a plain-language primer on mechanics.

What should you check before using Dydx swap?

Dydx swap deserves the same pre-trade review as any serious financial transaction. The user should know what asset or contract is being traded, what collateral is at risk, what order type is being used, and what could happen if the market moves against the position. A simple interface can make a complex trade feel casual, which is exactly why review matters.

Dydx swap users should also check whether the market is restricted, paused, newly listed, or unusually volatile. New and smaller markets can have wider spreads and less depth. During high volatility, quoted prices may change quickly, and a market order can fill at a worse level than expected. Setting realistic slippage limits, using limit orders when appropriate, and avoiding oversized trades can reduce avoidable execution problems.

Finally, Dydx swap decisions should be grounded in official, current information. Interfaces, supported assets, fee schedules, chain support, and access rules can change. This article is educational and does not provide financial, legal, tax, or investment advice. Before trading, users should verify the latest details through official dYdX sources and consider whether the product is suitable for their location and experience level.

Why Dydx swap requires more than a quick click

Dydx swap is useful because it can make crypto trading feel more direct, but the convenience should not hide the mechanics. A swap-style screen may compress many decisions into a few fields: market, amount, side, collateral, leverage, and execution type. Each of those choices affects risk. The best users slow down enough to understand what the interface is asking them to approve.

Dydx swap is ultimately a trading action on a sophisticated decentralized platform. It can help eligible users access crypto markets, manage exposure, and use professional tools without the same custody model as a centralized exchange. It can also create fast losses when used without a plan. The practical takeaway is simple: learn the market, verify the current rules, start cautiously, and treat every Dydx swap as a real trade with real risk.

Reader rating: 4.9 / 5 based on 945 ratings

Questions and Answers

What does Dydx swap mean?

Dydx swap usually means using dYdX to trade through a simplified swap-style flow. Depending on the current interface and market, that may involve opening or closing a perpetual position or using available spot trading features. It is not always the same as a basic token swap, so users should confirm whether they are trading an underlying asset or a derivative contract.

Is Dydx swap the same as a perpetual swap?

Not always. A Dydx swap may refer to a simple trading flow on dYdX, while a perpetual swap is a specific derivative contract with no expiry date. Many dYdX trades involve perpetuals, so the two ideas often overlap. The key difference is that perpetuals include margin, funding rates, liquidation risk, and contract exposure rather than direct ownership of the underlying token.

What fees apply to Dydx swap trades?

Dydx swap costs may include trading fees, spread, slippage, funding payments for perpetual positions, and network or bridging costs depending on the workflow. The exact fee schedule and market rules can change, so users should verify current details in the official dYdX interface before trading. Looking only at the headline fee can miss important execution costs.

Can beginners use Dydx swap safely?

Beginners can learn the interface, but Dydx swap may involve advanced products, especially perpetual contracts. A cautious user should start with education, confirm the official site, avoid leverage until they understand margin, and review every order detail before signing. Crypto trading can result in losses, and a simple-looking swap screen does not remove market, wallet, or liquidation risk.

Does Dydx swap require a crypto wallet?

dYdX workflows generally involve wallet-based access or account setup connected to crypto assets. Users may need to connect a supported wallet, deposit collateral, bridge funds, or approve transactions depending on the current version of the platform. Because wallet prompts can authorize important actions, users should verify the site, read permissions carefully, and never share seed phrases or recovery keys.

How is Dydx swap different from swapping on an automated market maker?

An automated market maker usually swaps tokens through liquidity pools, where pricing is based on pool reserves and routing. Dydx swap activity is often closer to order-book trading or derivatives trading, especially for perpetual markets. That can offer advanced exposure and order behavior, but it also introduces margin, funding, liquidation, and position-management concerns that do not apply to every simple spot token swap.

Is Dydx swap available in every country?

No crypto trading product should be assumed available everywhere. dYdX access and specific features can depend on jurisdiction, terms of use, market restrictions, and the current interface. Users should verify eligibility through official dYdX sources before connecting a wallet or attempting to trade. This is especially important for derivatives such as perpetual contracts, which may face stricter regional limitations.

Search on Youtube!

Dydx swap

Privacy Policy

Terms of Service

Refund Policy

Dydx swap

Dydx swap fees

ECGSYN - A realistic ECG waveform generator 1.0.0

File: <base> / Java / ecgApplet.java (109,386 bytes)
/************************************************************************/
/*                                                                      */
/* 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( "<html> <body>" +
                                "<font size='3'>"+
                                "<table width='400' border='0' align='center' cellpadding='0' cellspacing='5'>" +
                                "  <tr> " +
                                "    <td height='50' align='left' valign='middle'><strong><font color='#FF0000' size='4' face='Arial, Helvetica, sans-serif'>ECGSYN " +
                                "      PARAMETER DOCUMENTATION</font></strong></td>" +
                                "  </tr>" +
                                "  <tr> " +
                                "       <td height='30' align='left' valign='top'><strong><font color='#0000FF'>GENERAL " +
                                "           INTERFACE</font></strong></td> "+
                                "  </tr>" +
                                "  <tr> " +
                                "      <td align='left' valign='top'> <table width='100%' border='0' cellspacing='5' cellpadding='5'>" +
                                "    <tr> " +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong>Approximate number of heart beats:</strong><br>" +
                                "        fjaklsdfjasldjasdjfgfagsdgfasdgfywerwaegsdgfwefasjkgiawegasfkgiawefaklsdgfaiwegfklasegfaiwegaklgawiegfafwgegfauiwegfkasdgfiawegfawiegfasdklgfialweugfasefiuawgefilugfawileugfawilegfaweilgfawilegfasiduflskdgfailwuegfawileusdjklgfawilesdfk</td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>ECG Sampling Frequency</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>Internal Sampling Frequency</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>Amplitude of additive uniform noise</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>Heart rate mean</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>Heart rate standard deviation</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "    <tr>" +
                                "      <td width='60'>&nbsp;</td>" +
                                "      <td><strong><dt>Seed</dt></strong>" +
                                "        <dd>definition</dd></td>" +
                                "    </tr>" +
                                "  </table></td>" +
                                "  </tr>" +
                                "</table>" +
                                "</font>" +
                                "</body> </html>");
        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 ([email protected])\nG. Clifford ([email protected])\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<mmax; m+=2) {
                            for (i=m; i<=n; i+=istep) {
                                    j= i + mmax;
                                    tempr=wr * data[(int)j] - wi * data[(int)j+1];
                                    tempi=wr * data[(int)j+1] + wi * data[(int)j];
                                    data[(int)j]= data[(int)i] - tempr;
                                    data[(int)j+1]= data[(int)i+1] - tempi;
                                    data[(int)i] += tempr;
                                    data[(int)i+1] += tempi;
                            }
                            wr=(wtemp=wr)*wpr-wi*wpi+wr;
                            wi=wi*wpr+wtemp*wpi+wi;
                    }
                    mmax=istep;
            }
        }

        /*
         * STANDARD DEVIATION CALCULATOR
         */
        /* n-by-1 vector, calculate standard deviation */
        private double stdev(double[] x, int n){
                int j;
                double add,mean,diff,total;

                add = 0.0;
                for(j=1;j<=n;j++)
                    add += x[j];

                mean = add/n;

                total = 0.0;
                for(j=1;j<=n;j++){
                   diff = x[j] - mean;
                   total += diff*diff;
                } 
                return (Math.sqrt(total/((double)n-1)));
        }        

        /*
         * THE ANGULAR FREQUENCY
         */
        private double angfreq(double t){
           int i = 1 + (int)Math.floor(t/h);
           return(2.0*PI/rrpc[i]);
        }

        /*--------------------------------------------------------------------------*/
        /*    THE EXACT NONLINEAR DERIVATIVES                                       */
        /*--------------------------------------------------------------------------*/
        private void derivspqrst(double t0,double[] x, double[] dxdt){

            int i,k;
            double a0,w0,r0,x0,y0,z0;
            double t,dt,dt2,zbase;
            double[] xi, yi;

            k = 5; 
            xi = new double[k + 1];
            yi = new double[k + 1];
            w0 = angfreq(t0);
            r0 = 1.0; x0 = 0.0;  y0 = 0.0;  z0 = 0.0;
            a0 = 1.0 - Math.sqrt((x[1]-x0)*(x[1]-x0) + (x[2]-y0)*(x[2]-y0))/r0;

            for(i=1; i<=k; i++)
                xi[i] = Math.cos(ti[i]);
            for(i=1; i<=k; i++)
                yi[i] = Math.sin(ti[i]);   


            zbase = 0.005* Math.sin(2.0*PI*fhi*t0);

            t = Math.atan2(x[2],x[1]);
            dxdt[1] = a0*(x[1] - x0) - w0*(x[2] - y0);
            dxdt[2] = a0*(x[2] - y0) + w0*(x[1] - x0); 
            dxdt[3] = 0.0;  

            for(i=1; i<=k; i++){
              dt = Math.IEEEremainder(t-ti[i], 2.0*PI);
              dt2 = dt*dt;
              dxdt[3] += -ai[i] * dt * Math.exp(-0.5*dt2/(bi[i]*bi[i])); 
            }
            dxdt[3] += -1.0*(x[3] - zbase);
        }

        /*
         * RUNGA-KUTTA FOURTH ORDER INTEGRATION
         */
        private void Rk4(double[] y, int n, double x, double h, double[] yout){
            int i;
            double xh,hh,h6;
            double[] dydx, dym, dyt, yt;

            dydx=  new double[n + 1];
            dym =  new double[n + 1];
            dyt =  new double[n + 1];
            yt  =  new double[n + 1];

            hh= h * 0.5;
            h6= h/6.0;
            xh= x + hh;

            derivspqrst(x,y,dydx);
            for (i=1; i<=n; i++)
                yt[i]=y[i]+hh*dydx[i];

            derivspqrst(xh,yt,dyt);
            for (i=1; i<=n; i++)
                yt[i]=y[i] + hh * dyt[i];

            derivspqrst(xh,yt,dym);
            for (i=1; i<=n; i++){
                    yt[i]=y[i] + h * dym[i];
                    dym[i] += dyt[i];
            }

            derivspqrst(x+h,yt,dyt);
            for (i=1; i<=n; i++)
                    yout[i]=y[i] + h6 * (dydx[i]+dyt[i]+2.0*dym[i]);
        }

        /*
         * GENERATE RR PROCESS
         */
        private void rrprocess(double[] rr, double flo, double fhi, 
                              double flostd, double fhistd, double lfhfratio,  
                              double hrmean, double hrstd, double sf, int n)
        {
            int i,j;
            double c1,c2,w1,w2,sig1,sig2,rrmean,rrstd,xstd,ratio;
            double df;//,dw1,dw2;
            double[] w, Hw, Sw, ph0, ph, SwC;

            w =  new double[n+1];
            Hw = new double[n+1];
            Sw = new double[n+1];
            ph0= new double[(int)(n/2-1 +1)];
            ph = new double[n+1];
            SwC= new double[(2*n)+1];

            w1 = 2.0*PI*flo;
            w2 = 2.0*PI*fhi;
            c1 = 2.0*PI*flostd;
            c2 = 2.0*PI*fhistd;
            sig2 = 1.0;
            sig1 = lfhfratio;
            rrmean = 60.0/hrmean;
            rrstd = 60.0*hrstd/(hrmean*hrmean);

            df = sf/(double)n;
            for(i=1; i<=n; i++)
               w[i] = (i-1)*2.0*PI*df;

            for(i=1; i<=n; i++){
              //dw1 = w[i]-w1;
              //dw2 = w[i]-w2;
              Hw[i] = (sig1*Math.exp(-0.5*(Math.pow(w[i]-w1,2)/Math.pow(c1,2))) / Math.sqrt(2*PI*c1*c1))
                    + (sig2*Math.exp(-0.5*(Math.pow(w[i]-w2,2)/Math.pow(c2,2))) / Math.sqrt(2*PI*c2*c2));
            }

            for(i=1; i<=n/2; i++)
               Sw[i] = (sf/2.0)* Math.sqrt(Hw[i]);

            for(i=n/2+1; i<=n; i++)
               Sw[i] = (sf/2.0)* Math.sqrt(Hw[n-i+1]);

            /* randomise the phases */
            for(i=1; i<=n/2-1; i++)
               ph0[i] = 2.0*PI*rand();

            ph[1] = 0.0;
            for(i=1; i<=n/2-1; i++)
               ph[i+1] = ph0[i];

            ph[n/2+1] = 0.0;
            for(i=1; i<=n/2-1; i++)
               ph[n-i+1] = - ph0[i]; 

            /* make complex spectrum */
            for(i=1; i<=n; i++)
               SwC[2*i-1] = Sw[i]* Math.cos(ph[i]);

            for(i=1; i<=n; i++)
               SwC[2*i] = Sw[i]* Math.sin(ph[i]);

            /* calculate inverse fft */
            ifft(SwC,n,-1);

            /* extract real part */
            for(i=1; i<=n; i++)
               rr[i] = (1.0/(double)n)*SwC[2*i-1];

            xstd = stdev(rr,n);
            ratio = rrstd/xstd; 

            for(i=1; i<=n; i++)
               rr[i] *= ratio;

            for(i=1; i<=n; i++)
               rr[i] += rrmean;

        }

        /*
         * DETECT PEAKS
         */
        private void detectpeaks(double[] ipeak, double[] x, double[] y, double[] z, int n){
            int i, j, j1, j2, jmin, jmax, d;
            double thetap1, thetap2, thetap3, thetap4, thetap5;
            double theta1, theta2, d1, d2, zmin, zmax;

            thetap1 = ti[1];
            thetap2 = ti[2];
            thetap3 = ti[3];
            thetap4 = ti[4];
            thetap5 = ti[5];

            for(i=1; i<=n; i++)
               ipeak[i] = 0.0;

            theta1 = Math.atan2(y[1],x[1]);

            for(i=1; i<n; i++){
              theta2 = Math.atan2(y[i+1], x[i+1]);

              if( (theta1 <= thetap1) && (thetap1 <= theta2) ){
                d1 = thetap1 - theta1;
                d2 = theta2 - thetap1;
                if(d1 < d2)
                    ipeak[i] = 1.0;
                else
                    ipeak[i+1] = 1.0;
              }else if( (theta1 <= thetap2) && (thetap2 <= theta2) ){
                d1 = thetap2 - theta1;
                d2 = theta2 - thetap2;
                if(d1 < d2)
                    ipeak[i] = 2.0;
                else
                    ipeak[i+1] = 2.0;
              }else if( (theta1 <= thetap3) && (thetap3 <= theta2) ){
                d1 = thetap3 - theta1;
                d2 = theta2 - thetap3;
                if(d1 < d2)
                    ipeak[i] = 3.0;
                else
                    ipeak[i+1] = 3.0;
              }else if( (theta1 <= thetap4) && (thetap4 <= theta2) ){
                d1 = thetap4 - theta1;
                d2 = theta2 - thetap4;
                if(d1 < d2)
                    ipeak[i] = 4.0;
                else
                    ipeak[i+1] = 4.0;
              }else if( (theta1 <= thetap5) && (thetap5 <= theta2) ){
                d1 = thetap5 - theta1;
                d2 = theta2 - thetap5;
                if(d1 < d2)
                    ipeak[i] = 5.0;
                else
                    ipeak[i+1] = 5.0;
              }
              theta1 = theta2; 
            }

            /* correct the peaks */
            d = (int)Math.ceil(sfecg/64);
            for(i=1; i<=n; i++){ 
                if( ipeak[i]==1 || ipeak[i]==3 || ipeak[i]==5 ){

                    j1 = (1 > (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);
        }
    }
}