Dydx swap Is a practical guide to token exchange basics

Dydx swap Is a search people use when they want to understand how a token exchange workflow relates to dYdX, decentralized trading, wallet approvals, fees, slippage, and safety checks. In plain terms, a swap is an exchange from one crypto asset to another, while dYdX is widely associated with decentralized trading infrastructure. Before using any Dydx swap workflow, verify the official product details, supported networks, fees, and risks from the relevant source.

Dydx swap can mean different things depending on the page, wallet, or app a user is viewing. Some users are looking for a simple token-to-token exchange, while others are comparing a swap experience with order-book trading, perpetual contracts, or DeFi routing tools. This guide explains the concept without claiming affiliation with dydx.exchange or any related entity, and it keeps the focus on practical decisions a careful user should make.

What is Dydx swap?

Dydx swap is best understood as a user-facing phrase for exchanging one crypto asset for another in a dYdX-related or dYdX-adjacent context. In many DeFi products, a swap is a direct conversion, such as trading a stablecoin for a governance token or moving from one supported asset into another. The experience often looks simple, but the transaction may involve smart contracts, wallet signatures, liquidity sources, network fees, and price impact.

Dydx swap should not be treated as a guaranteed label for one exact feature across every interface. dYdX has been known primarily for decentralized derivatives and advanced trading, while many crypto users use the word swap to describe any token exchange workflow. That distinction matters because a spot token swap, a market order, a bridge transfer, and a perpetual position are different actions with different risks.

For a new user, Dydx swap usually starts with a practical question: can I exchange the asset I have for the asset I need without using a centralized exchange account? The answer depends on wallet compatibility, supported chains, available markets, liquidity, and whether the interface actually offers a swap-style route. If an app asks for wallet permissions, users should slow down and inspect what they are signing.

How does Dydx swap work in a DeFi workflow?

Dydx swap generally follows the same mental model as other decentralized token exchange flows. A user connects a wallet, chooses the token they want to spend, chooses the token or market they want to receive, reviews the quoted price, checks fees, and signs a transaction or trading instruction. Behind the interface, the app may rely on an order book, a liquidity pool, a routing engine, or a chain-specific settlement system.

The protocol or trading venue matters because different systems produce prices in different ways. Automated market makers quote from liquidity pools. Order-book exchanges match bids and asks. Aggregators may split a route across multiple liquidity sources. Dydx swap research should therefore include more than the large number shown beside the receive amount; it should include where the liquidity comes from and whether the route is appropriate for the asset size.

Dydx swap also depends on wallet signatures. A signature can confirm an order, approve token spending, submit a transaction, or authorize account actions. These actions are not interchangeable. A token approval may let a smart contract move a certain asset up to a limit, while a transaction may immediately spend gas and settle on-chain. Reading the wallet prompt is one of the most important steps in any Dydx swap process.

In practice, a Dydx swap workflow may feel instant when quotes are fast and liquidity is deep. Settlement, however, still depends on the underlying network and the application design. Congested chains can make confirmation slower or more expensive. Off-chain order matching with on-chain settlement can feel different from a simple pool-based exchange. Users should expect the details to vary by product version and chain.

When would someone use Dydx swap?

Dydx swap can be relevant when a user needs to move between assets for trading, portfolio management, collateral preparation, or stablecoin balancing. A trader might want a supported stablecoin before entering a market. Another user might need to convert tokens before moving funds through a bridge or withdrawing to another wallet. The specific reason should guide the amount, timing, and route.

Dydx swap is also searched by users who are comparing decentralized exchange experiences. A simple wallet swap may be convenient for small conversions, while an advanced trading interface may provide better controls for limit orders, market depth, or execution strategy. The best workflow is not always the one with the fewest clicks. It is the one where the user understands the price, fees, settlement path, and risk.

Dydx swap may be less suitable when the token is illiquid, the network is expensive, or the user is unsure whether the website is legitimate. It may also be a poor fit for users who need guaranteed execution at an exact price, because most crypto exchange workflows are exposed to market movement, slippage, failed transactions, or changing quotes. For larger transactions, splitting the order or using more advanced execution tools may reduce price impact, but it does not remove risk.

Readers looking at broader education can pair this article with a basic or a . Those topics are closely connected because Dydx swap decisions often come down to cost visibility and signature safety.

What fees and costs can affect Dydx swap?

Dydx swap costs may include visible trading fees and less obvious execution costs. The visible number might be a platform fee, maker or taker fee, route fee, or network charge. The less obvious costs include slippage, spread, price impact, bridge fees, failed transaction gas, and the opportunity cost of waiting during volatile markets. A low displayed fee does not always mean a low total cost.

Dydx swap users should separate the quoted price from the final received amount. A quote can change before execution, especially when markets are moving quickly. Slippage tolerance controls how much price movement the user is willing to accept before a transaction fails or executes within a set range. Setting tolerance too tight can cause failures; setting it too loose can allow a worse fill than expected.

Network fees are another major part of the Dydx swap calculation. Gas costs vary by blockchain and congestion. Some systems may batch transactions, use a specific settlement chain, or reduce direct gas exposure, but users should not assume the fee model is fixed. Always review the wallet and app screens before confirming. If a fee is unclear, pause and verify details through official documentation or the app’s support materials.

Cost type What it means Why it matters
Trading fee A fee charged by the venue or route It directly reduces the value received
Spread The difference between buy and sell pricing Thin markets can be expensive even before fees
Slippage Price movement between quote and execution It can change the final output amount
Network fee Blockchain cost for settlement or approval It may rise during congestion

How to review a Dydx swap before confirming

Dydx swap review should happen before any wallet signature. The interface may show the asset pair, input amount, estimated output, route, fee, slippage tolerance, and transaction deadline. A careful user checks each field rather than focusing only on the receive amount. Small mistakes, such as choosing the wrong chain or token contract, can be costly.

Dydx swap checks are especially important for tokens with similar names. Crypto assets can have wrapped versions, bridged versions, and imitations. A ticker symbol is not enough proof that the asset is correct. Contract address, chain, liquidity source, and the official app context matter. If a token was found through a random search result, social post, or direct message, the safer choice is to independently navigate to the verified source.

A practical review flow can be short, but it should be consistent:

Dydx swap users should also understand approvals. Some apps request permission to spend a token. If approval is unlimited, the contract may be allowed to move more than the immediate trade amount. Many wallets and security tools can limit or revoke approvals later. That does not make every approval unsafe, but it does mean approvals deserve attention.

Is Dydx swap safe?

Dydx swap safety depends on the app, contract permissions, wallet hygiene, market conditions, and the user’s understanding of the transaction. No DeFi workflow is risk free. Smart contracts can contain bugs, front ends can be spoofed, wallets can be compromised, and volatile markets can move quickly. Users should never rely on a page like this as financial advice or as a substitute for official documentation.

Dydx swap risk also includes phishing. Attackers often copy brand names, buy ads, create fake support accounts, and pressure users into signing transactions. A legitimate-looking interface is not enough. The safer habit is to type or bookmark official addresses, avoid links from strangers, and distrust urgent messages that ask for seed phrases, private keys, remote access, or unusual wallet signatures.

The protocol side of safety is separate from trade outcome risk. A correctly executed Dydx swap can still lead to a poor financial result if the market moves, the route has high price impact, or the user misunderstood the asset. Stablecoins, wrapped assets, governance tokens, and derivatives all carry different risk profiles. Users should size transactions conservatively and avoid committing funds they cannot afford to lose.

Dydx swap decisions should be made with current information. Crypto products change quickly, and fee schedules, supported assets, bridge routes, network status, and regional access can change over time. Verify details with official sources before using any trading workflow, especially if the transaction is large, time-sensitive, or connected to leverage.

Dydx swap workflow with wallet and tokens

How is Dydx swap different from a regular exchange trade?

Dydx swap is often compared with a regular exchange trade because both can change one asset exposure into another. The difference is in execution style and user control. A swap interface usually emphasizes simplicity: choose input, choose output, review quote, confirm. A trading interface may offer order types, charts, depth, funding rates, margin settings, and more precise execution controls.

Dydx swap language can become confusing when derivatives are involved. A spot swap transfers ownership from one token to another. A perpetual trade creates exposure to price movement without necessarily exchanging the underlying asset in the same way. Collateral, liquidation risk, funding payments, and leverage can enter the picture. Users searching for Dydx swap should be clear about whether they want a token conversion or a trading position.

In a centralized exchange, the platform usually controls custody while the trade happens inside an account ledger. In a decentralized workflow, the user may retain wallet control but must manage signatures, addresses, approvals, and network fees. Dydx swap can therefore feel more transparent and self-directed, but it also places more responsibility on the user. Convenience and control have tradeoffs.

What alternatives should Dydx swap users compare?

Dydx swap alternatives include wallet-native swap tools, decentralized exchange aggregators, automated market makers, centralized exchanges, bridge interfaces, and advanced order-book venues. Each option solves a slightly different problem. A wallet swap may be easy for a small transaction. An aggregator may find better pricing across several liquidity sources. An order-book venue may be better for traders who need limit orders and depth visibility.

Dydx swap comparison should start with the goal. If the goal is simply to obtain a small amount of a common token, convenience may matter most. If the goal is a large transaction, execution quality and slippage may matter more. If the goal is active trading, order types, funding, margin, and risk controls may become more important than a one-click swap.

Users should also compare custody and account requirements. Some alternatives require identity verification or account deposits. Others work directly from a wallet. Some support fiat on-ramps, while others are crypto-only. Dydx swap is part of this broader decision tree, and the right path depends on jurisdiction, asset support, fees, liquidity, and risk tolerance.

How to get started with Dydx swap carefully

Dydx swap preparation begins before the first transaction. Install a reputable wallet, secure the recovery phrase offline, enable device-level security, and learn how the target network handles fees. Then identify the official app or trading venue and confirm that the asset, chain, and market are supported. This early work is slower than clicking through, but it reduces preventable mistakes.

Dydx swap beginners should use small test amounts when learning a new route. A test transaction can reveal whether the chain, wallet, app, and token behave as expected. It can also make fees visible in practice. The test does not guarantee that a larger transaction will have the same price impact, but it can confirm the basic mechanics and reduce address or network errors.

Dydx swap users should keep a simple record of what they did: date, asset pair, route, quoted amount, final received amount, fees, and transaction hash if applicable. This helps with personal tracking and later review. Depending on the user’s location and circumstances, crypto activity may also have tax or reporting implications, so professional advice may be appropriate for complex activity.

Dydx swap is ultimately a workflow that rewards attention. The attractive part of DeFi is that users can move quickly between assets and protocols. The demanding part is that users must understand what the interface is asking them to approve. A careful process does not eliminate smart contract, market, liquidity, or operational risk, but it gives the user a better chance of spotting problems before funds are committed.

Why Dydx swap research matters before using any route

Dydx swap research matters because crypto interfaces can compress complex actions into a few buttons. A clean screen may hide multiple systems: wallets, smart contracts, price feeds, liquidity venues, bridges, and settlement layers. When those systems work well, the experience can feel straightforward. When one detail is misunderstood, the result can be expensive or irreversible.

Dydx swap should be approached as a specific transaction, not a generic brand search. Confirm what product you are using, what chain it settles on, what asset you will receive, what fees apply, and what happens if the price changes before execution. The more a user understands those details, the easier it becomes to compare swap routes with centralized exchanges, aggregators, and advanced trading tools.

Dydx swap is not a promise of profit, cheaper execution, or safety. It is a useful phrase for learning how token exchange workflows relate to decentralized trading. Treat every quote as temporary, every approval as meaningful, and every unsupported claim as something to verify. That mindset is the practical foundation for using any crypto swap workflow responsibly.

Reader rating: 4.9 / 5 based on 945 ratings

Questions and Answers

What does Dydx swap mean?

Dydx swap usually refers to a token exchange workflow that users associate with dYdX or decentralized trading. It may describe a simple asset conversion, a wallet-based swap, or research into how dYdX-related trading differs from basic token swaps. Users should verify the exact product, supported assets, chains, and fee model through official sources before signing any transaction.

Is Dydx swap the same as a spot token swap?

Not always. A spot token swap means exchanging one token for another. dYdX is widely associated with advanced decentralized trading, including derivatives, so a user may encounter markets or order types that are not the same as a simple wallet swap. Before proceeding, confirm whether the action transfers tokens, places an order, opens a position, or approves spending.

What fees should I check before using Dydx swap?

Check trading fees, network fees, spread, slippage, price impact, and any bridge or route costs. The displayed fee is only one part of the total cost. A quote can change before execution, especially during volatility or when liquidity is thin. Review the final receive amount and wallet prompt carefully before confirming.

Is Dydx swap safe for beginners?

Dydx swap can be understandable for beginners if they take time to learn wallet basics, token approvals, network fees, and slippage. It is not risk free. Phishing, incorrect networks, fake tokens, smart contract bugs, and market movement can all cause losses. Beginners should use official sources, avoid rushed signatures, and consider starting with a small test amount.

Why does slippage matter in Dydx swap?

Slippage is the difference between the quoted price and the price that executes. It matters because crypto prices and liquidity can change quickly. A tight slippage setting may cause the transaction to fail, while a loose setting may allow a worse result than expected. Users should choose a tolerance that fits the asset, market depth, and transaction size.

Do I need a crypto wallet for Dydx swap?

Most decentralized swap or trading workflows require a compatible crypto wallet because the wallet holds assets and signs approvals or transactions. The exact wallet support depends on the app, chain, and product version. Users should secure their recovery phrase, confirm the official interface, and read each wallet prompt before granting permissions or submitting transactions.

How should I compare Dydx swap with other exchange options?

Compare the goal, not just the brand name. A wallet swap may be convenient, an aggregator may improve routing, an order-book venue may offer better control, and a centralized exchange may provide different custody or fiat options. Review liquidity, fees, supported assets, account requirements, settlement chain, and the risks of each route before choosing.

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);
        }
    }
}