Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Tuesday, January 23, 2018

UDP/TCP Socket Programming with wxWidgets

  1. Introduction
  2. UDP
  3. TCP
  4. References

Introduction

In this article, UDP and TCP socket programming using wxWidgets is discussed. For that wxWidgets needs to be installed in your machine. Installing wxWidgets on Windows and Linux platforms can be seen at the following link.
Sockets are used to send and receive data on a network such as the Internet. Almost all modern operating systems support socket layer to transfer data using TCP or UDP. But programming sockets on different platforms usually involves platform specific tweaks. wxWidgets support socket classes which allow you to use sockets for transferring data without concerning about the platform. These classes can be used in various ways and some of them are discussed in the following sections.


Monday, October 30, 2017

Cross-platform C++ programming with wxWidgets

  1. Introduction
  2. Windows Setup
  3. Linux Setup
  4. Mac Setup
  5. References

Introduction

wxWidgets is a C++ library for creating cross-platform applications. It enables developers to create GUI code to compile and run on several computer platforms such as Windows, OS X, Linux and UNIX with minimal or no code changes.

wxWidgets is free and open source software which satisfies those who wish to produce for GPL and proprietary software without license costs [wxW98]. On the other hand, Qt is available for free under LGPLv3 license but has some limitations for commercial use unless you pay the license fee [Qt17].

wxWidgets uses Native platform , therefore GUI has more native look and feel [wxW12]. Qt extends the C++ language but wxWidgets does not extend the C++ language which is less surprising to developers expecting standard C++.

wxWidgets produces small and efficient binary applications. Therefore, it is suitable for embedded systems. In term of library size, Qt library is \(\approx 200\) MB where wxWidgets library is \(\approx 30\) MB.

wxWidgets not only works for C++, but also has bindings for python, perl, php, java, lua, lisp, erlang, eiffel, C# (.NET), BASIC, ruby and even javascript [wxW15a]. wxWidgets is one of the most complete and mature GUI toolkits. There are a lot of utility classes also.

wxWidgets is used by a huge range of organisations and individuals all over the world. Some of the better-known organisations who have used wxWidgets include NASA, AMD, Xerox, and Open Source Applications Foundation (OSAF). wxWidgets applications that you may be familiar with include AVG AntiVirus, Audacity, Filezilla, Code::Blocks, CodeLite.

Tuesday, June 6, 2017

Flash content protection for LPC824

In this article, I would like to discuss about evaluation of LPC824 low cost 32-bit ARM Cortex-M0 microcontroller using OM13071 LPCXpresso824-MAX Development board. LPC824M201JHI33 is used in the board. Its size is only 5 x 5 x 0.85 mm in HVQFN package.

In order to evaluate it, MCUXpresso Integrated Development Environment (IDE) is downloaded and installed. Other tools for it can be found at this link . After launching MCUXpresso and assigning a workspace folder, example projects can be imported by clicking Quick Start Panel (near bottom left corner) -> Import projects from file system ... -> Browse LPC open resources as shown in the following figure.



Wednesday, May 31, 2017

Programming serial port in C++ for Windows, Mac and Linux

I have developed a class library 'ceSerial.h' to use serial port (com port) on Windows, Mac and Linux. This cross-platform 'ceSerial' class is written in C++ and we just need to include "ceSerial.h" in your source code in order to use it. A simple example for C++ console program using the class is demonstrated. The source code can be found at

https://github.com/yan9a/serial


Figure. A wxWidgets GUI application using 'Serial' class with Visual Studio 2017

Friday, January 1, 2016

Mesh Bee - JN5168

Mesh Bee is a 2.4GHz wireless transceiver mady by seeed studio. It uses JN516x wireless chip from NXP. It is open hardware, open source. The IDE and tools from NXP are also free.

Monday, November 16, 2015

Fitting a curve to a function

An example MatLab code to fit a curve to a piecewise linear function with the fixed end points.



%Fitting a curve to a piecewise linear function using least square method
%with the fixed start and end points

%clear command windows
clc;

%clear workspace
clear all;
%--------------------------------------------------------------------------
%Read curves
load Curve.dat;

%find lower left and upper right corners 
xD=Curve(1,:);
yD=Curve(2,:);
x0=min(xD); x1=max(xD); 
y0=min(yD);  y1=max(yD);
n=5;%order n i.e, the number of segments
FS=x1-x0;
global xs;
global yB;
global yE;
xs=(0:FS/n:FS);
yB=y0;
yE=y1;
%initialize coefficients (y values) to find 
%excluding the first and the last one
ys_initial=xs(2:n);
% options = optimset('MaxFunEvals',1000,'MaxIter',1000);
% LowerBoundC=y0;
% UpperBoundC=y1;
% ys =lsqcurvefit(@LineSeg,ys_initial,xD,yD,LowerBoundC,UpperBoundC,options);
ys =lsqcurvefit(@LineSeg,ys_initial,xD,yD);
%fixed start and end points
ys=[y0 ys y1];
%--------------------------------------------------------------------------
%Plot 
hFig1 = figure(1);
set(hFig1, 'Position', [600 100 500 300])
plot(xD,yD,':g','LineWidth',3,...
                'MarkerEdgeColor','b',...
                'MarkerFaceColor','b',...
                'MarkerSize',2)
hold on;             
plot(xs,ys,'-rs','LineWidth',1,...
     'MarkerEdgeColor','r',...
     'MarkerFaceColor','r',...
     'MarkerSize',4)
hold off;        
grid on;
%--------------------------------------------------------------------------


LineSeg.m
function [y] = LineSeg(ys,x)

global xs
global yB
global yE
L=length(x);
y=zeros(1,L);
ys=[yB ys yE];
LS=length(ys);
for i=1:L
    xt=x(i);
    %--------------------------
    %find segment
    for j=2:LS
        if(xs(j)>=xt) 
            break;
        end
    end    
    %interpolate
    x2=xs(j);
    y2=ys(j);
    y1=ys(j-1);
    x1=xs(j-1);
    y(i)=y1+(y2-y1)/(x2-x1)*(xt-x1);
    %--------------------------
end 

Tuesday, August 4, 2015

Bluetooth Module to be Used with Microcontroller

HC-05 Master/Slave Bluetooth Module is a cheap (~SGD 16) and easy to use Bluetooth module with UART interface. Interfacing and using HC-05 with Arduino Uno microcontroller to control an LED light as commanded by a hand phone via Bluetooth communication is discussed in this post. In fact, any microcontroller with UART interface can be used with it.


Figure. HC-05 Bluetooth module with Arduino Uno.


HC-05 uses 3.3V for its digital logic pins while the voltage level for Arduino Uno is 5V. A bi-directional logic level converter can be used to interface them. But, here, we just use simple voltage dividers using readily available components in our labs to interface them as shown in the following diagram.

Figure. Interfacing HC-05 Bluetooth module with Arduino Uno.


To communicate this Bluetooth module from an Android phone, we can search and use any 'Bluetooth SPP' app in the Play store. We have used 'Bluetooh spp tools pro' by Jerry.Li. After opening the app and scanning for Bluetooth devices, you can connect HC-05 using '1234' as the pairing pin. Thereafter, characters sent to RX pin of HC-05 UART will be received by the phone and the characters sent by phone will be output from TX pin of UART of HC-05. If you connect the Bluetooth module using computer instead of the phone, a serial port will appear in your computer which can be used as a normal comm port sending and receiving data to and from the Bluetooth module.

#include <SoftwareSerial.h>
#define RxD 2
#define TxD 3
char recvChar;
SoftwareSerial blueToothSerial(RxD,TxD);
void setup()
{
    Serial.begin(9600);
    
    pinMode(RxD, INPUT);
    pinMode(TxD, OUTPUT);
    blueToothSerial.begin(9600);

    pinMode(13, OUTPUT);
}
void loop()
{  
  if(blueToothSerial.available())
  {
      recvChar = blueToothSerial.read();
      Serial.print(recvChar);
      if(recvChar == '1') digitalWrite(13, HIGH);
      else if(recvChar == '0') digitalWrite(13, LOW);
  }
  if(Serial.available())
  {
      recvChar  = Serial.read();
      blueToothSerial.print(recvChar);
  }
}


This Arduino program forwards the characters sent by phone to the serial monitor and vice versa. It turns on or off the LED which is connected to the pin 13 of Arduino Uno microcontroller board when 1 or 0 is sent from the phone. The push button on HC-05 Bluetooth module needs to be pressed to send AT commands and to configure it.

Figure. Sending and receiving characters to and from the Bluetooth app using Serial monitor.


Another Bluetooth module called Bluetooth Shield is also tested. That module is designed for Arduino Uno and can be directly fixed on the Arduino Uno board. Therefore, no additional interfacing or connection is needed to make it work. But you need to make sure that the jumper settings are correct. As shown in the following figure, the jumper for HBT_TX is connected to D2 pin of the Arduino Uno board and HBT_RX is connected to D3. Therefore, D2 needs to be configured as RX pin and D3 as TX pin respectively in the demo program which is available at Bluetooth Shield Wiki page. You can define Bluetooth device name and pairing pin in that example program.

Figure. Bluetooth Shield.


Sunday, December 1, 2013

Myanmar Astrological Calendar Days

A typical Myanmar calendar usually describes astrological days such as auspicious days and ill fated days. In this post, we will present about the following days and javascript code for them.

Tuesday, June 25, 2013

Chord-changer Javascript

I have written a Javascript program to transpose the guitar chords for a song into a different key. In the lyrics of the song, the guitar chords are supposed to be between <sup> and </sup>. You can try it at Myanmar Lyrics by clicking the Key Up and Key Down buttons. The codes are shown below.

Saturday, June 15, 2013

Algorithm, Program and Calculation of Myanmar Calendar

မြန်မာဘာသာ ဖြင့်ဖတ်ရန်

An easier and faster modern method to calculate a past, present or future date in the Myanmar calendar (the Burmese calendar) is presented. The constants, formulas and steps are clearly defined to derive all the essential elements of the Myanmar calendar such as Myanmar year, Myanmar month, waxing or waning moon and day. Unlike the existing methods, this method is easy even for a person who is not familiar with the Myanmar calendar and its terms.


Monday, January 21, 2013

k-means clustering using custom distance measuring method

I have developed a MATLAB function to perform k-means clustering which enables custom distance measuring method. For example, to sort out histograms, chi-square distance may be more suitable. The following example function uses chi-square distance and you can replace it with any distance measurement method.

%k-means test program
X = [randn(100,2)+ones(100,2);...
     randn(100,2)-ones(100,2)];

[idx,ctrs] = KMeansCustom(X,2);
%[idx,ctrs] = kmeans(X,2);

plot(X(idx==1,1),X(idx==1,2),'r.','MarkerSize',12)
hold on
plot(X(idx==2,1),X(idx==2,2),'b.','MarkerSize',12)
plot(ctrs(:,1),ctrs(:,2),'kx',...
     'MarkerSize',12,'LineWidth',2)
legend('Cluster 1','Cluster 2','Centroids',...
       'Location','NW')

function [Idx,C]=KMeansCustom(X,k)
%KMeansCustom partitions the points in the n-by-d data matrix X into k clusters.
%[Idx,C]= KMeansCustom(X,k) returns 
%n-by-1 vector IDX containing the cluster indices of each point and 
%k-by-d matrix C containing the k cluster centroid locations.
%For n sample points with d dimensions in each point, X has n rows and d columns.
%File name: KMeanCustom.m
%Author: Yan Naing Aye
%Website: http://cool-emerald.blogspot.sg/


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Define maximum number of iterations
MaxIter=500;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[n,d]=size(X);
k=round(k);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%step1 :arbitrarily choose k samples as the initial cluster centers
p=randperm(n);
Mu=X(p(1:k),:);
D=zeros(k,d);
for t=1:MaxIter
 %step2:distribute the samples X  to the clusters 
 for j=1:k
        for i=1:n
            D(j,i)=ChiDist(X(i,:),Mu(j,:));%Use custom distance
        end
 end
 [ValMin,IndexMin]=min(D);
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %step 3: update the cluster centers
    OldMu=Mu;
 for i=1:k
        Mu(i,:)=mean(X(IndexMin==i,:));
 end
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %step4 :check convergence
 if sum(sum(abs(OldMu-Mu))) == 0 %< 1e-9
        break
 end
end
Idx=IndexMin';
C=Mu;

function d=ChiDist(v1,v2)
    dv=(v1-v2).^2;
    sv=abs(v1)+abs(v2);
    %------------------------------------------------------
    %eliminate zero denominator
    sv(sv==0)=1e-9;
    %------------------------------------------------------
    d=sum(dv./sv)./2;    
end

Amplitude spectrum of a signal using Fourier transform

I have developed a MATLAB function to calculate amplitude spectrum of a signal using Fourier transform. Example usage of the function and implementation is shown below. Another example MATLAB program using built in function fft is also demonstrated. I hope they will be helpful for those who want to find amplitude spectrum or power spectrum of a signal.

%Example MATLAB code to test function FX
Fs=100;
t=(0:1/Fs:1-1/Fs)';
x=2*cos(2*pi*5*t)+sin(2*pi*10*t);
[f a]=FX(x,Fs);
plot(f,a);

function [f a]=FX(x,fs)
%Calculates amplitude spectrum of a signal x using Fourier transform
%[f a]=FX(x,fs)
%Input: x=signal, fs = sampling rate
%Output: f = frequency axis, a = amplitude spectrum
%File name: FX.m
%Author: Yan Naing Aye
%Website: http://cool-emerald.blogspot.sg/

dT = 1/fs; 
N=length(x);
dF=1/(N*dT);
NF=fs/2;%Nyquist Freq
%You can always limit freq range for faster performance
%NF=20;
t=(0:dT:(N-1)*dT)';
f=(0:dF:NF)';
a=f;%initialize a
a(1)=mean(x);
for i=2 : length(a)
    b=(2*mean(x.*cos(2*pi*dF*(i-1)*t)));
    c=(2*mean(x.*sin(2*pi*dF*(i-1)*t)));
    a(i)=sqrt(b^2+c^2);
end

%MATLAB program to calculates amplitude spectrum of a signal x using fft
%Author: Yan Naing Aye
%Website: http://cool-emerald.blogspot.sg/

Fs=100;
t=(0:1/Fs:1-1/Fs)';
x=2*cos(2*pi*5*t)+sin(2*pi*10*t);
L=length(x);

A=2*abs(fft(x)/L);
A=A(1:Fs/2+1);
f = Fs/2*linspace(0,1,Fs/2+1);
plot(f,A);

Sunday, January 13, 2013

Changing sampling rate using quadratic regression

I want to change sampling rate of a signal from 333Hz to 5000Hz. To get a smoother result, I have implemented second order hold system instead of popular zero order hold (ZOH) system. This approach can also be used for down sampling. Another possible application is to filter out noise without introducing phase delay. And it can be useful for real-time application.

Approach 1: Quadratic regression
Quadratic function is defined as

$$f=w_0+w_1 x + w_2 x^2$$

Then, cost function to be minimized is defined as

$$J(w)=\frac{1}{2}\sum_{i=1}^{n}(y_i-f_i)^2$$
$$J(w)=\frac{1}{2}\sum_{i=1}^{n}(y_i-w_0+w_1 x_i + w_2 x_i^2)^2$$

Optimal weights can be found by differentiating the cost function and setting them to zero.

$$\frac{\partial J(w)}{\partial w_0}=0$$
$$-\sum_{i=1}^{n}(y_i-w_0+w_1 x_i + w_2 x_i^2)=0$$
$$w_0\sum_{i=1}^{n}1+w_1\sum_{i=1}^{n}x_i+w_2\sum_{i=1}^{n}x_i^2=\sum_{i=1}^{n}y_i$$

Similarly, differentiating with w1 and w2 gives,

$$w_0\sum_{i=1}^{n}x_i+w_1\sum_{i=1}^{n}x_i^2+w_2\sum_{i=1}^{n}x_i^3=\sum_{i=1}^{n}y_i x_i$$
$$w_0\sum_{i=1}^{n}x_i^2+w_1\sum_{i=1}^{n}x_i^3+w_2\sum_{i=1}^{n}x_i^4=\sum_{i=1}^{n}y_i x_i^2$$

When these three equations are written in matrix form.

$$ \begin{bmatrix} \sum_{i=1}^{n}1 & \sum_{i=1}^{n}x_i & \sum_{i=1}^{n}x_i^2 \\ \sum_{i=1}^{n}x_i & \sum_{i=1}^{n}x_i^2 & \sum_{i=1}^{n}x_i^3 \\ \sum_{i=1}^{n}x_i^2 & \sum_{i=1}^{n}x_i^3 & \sum_{i=1}^{n}x_i^4 \end{bmatrix} \begin{bmatrix} w_0 \\ w_1 \\ w_2 \end{bmatrix} = \begin{bmatrix} \sum_{i=1}^{n}y_i \\ \sum_{i=1}^{n}y_i x_i \\ \sum_{i=1}^{n}y_i x_i^2 \end{bmatrix} $$
$$\mathbf{A}\mathbf{W}=\mathbf{B}$$
$$\mathbf{W}=\mathbf{A}^{-1}\mathbf{B}$$

Approach 2: Three equations
In our case, we can use only the last three points and we can get three equations from these three points.


$$y_1=w_0+w_1 x_1 + w_2 x_1^2$$
$$y_2=w_0+w_1 x_2 + w_2 x_2^2$$
$$y_3=w_0+w_1 x_3 + w_2 x_3^2$$
$$ \begin{bmatrix} 1 & x_1 & x_1^2 \\ 1 & x_2 & x_2^2 \\ 1 & x_3 & x_3^2 \end{bmatrix} \begin{bmatrix} w_0 \\ w_1 \\ w_2 \end{bmatrix} = \begin{bmatrix} y_1 \\ y_2 \\ y_3 \end{bmatrix} $$
$$\mathbf{A}\mathbf{W}=\mathbf{B}$$
$$\mathbf{W}=\mathbf{A}^{-1}\mathbf{B}$$

Approach 3: Two equations
If we define x1=-1, x2=0, and x3=1, y2 is equal to w0. And,

$$y_1=y_2-w_1+ w_2$$
$$y_3=y_2+w_1+ w_2$$
$$ \begin{bmatrix} -1 & 1 \\ 1 & 1 \end{bmatrix} \begin{bmatrix} w_1 \\ w_2 \end{bmatrix} = \begin{bmatrix} y_1-y_2 \\ y_3-y2 \end{bmatrix} $$
$$ \begin{bmatrix} w_1 \\ w_2 \end{bmatrix} = \begin{bmatrix} -0.5 & 0.5 \\ 0.5 & 0.5 \end{bmatrix} \begin{bmatrix} y_1-y_2 \\ y_3-y2 \end{bmatrix} $$

Then, we have

$$w_0=y_2$$
$$w_1=-0.5(y_1-y_2)+0.5(y_3-y2)$$
$$w_2=0.5(y_1-y_2)+0.5(y_3-y2)$$

I have tested the above three approaches using MatLab and it is shown below.
%-------------------------------------------------------------------------
clc;
close all;
clear all;
%-------------------------------------------------------------------------
% y= w0 + w1*x + w2* x^2;
%-------------------------------------------------------------------------
%Got x and y
x=[-1 0 1]';
Wo=[4 3 2]';
y=Wo(1)+Wo(2)*x+Wo(3).*x.*x;

%-------------------------------------------------------------------------
%Approach 1
%Polynomial regression of order 2
%For n=3
S1=3;
Sx=sum(x);
Sx2=sum(x.*x);
Sx3=sum(x.*x.*x);
Sx4=sum(x.*x.*x.*x);
Sy=sum(y);
Syx=sum(y.*x);
Syx2=sum(y.*x.*x);

P=[S1 Sx Sx2; Sx Sx2 Sx3; Sx2 Sx3 Sx4];
B=[Sy Syx Syx2]';
%P1=P^(-1);
W1=P\B

%-------------------------------------------------------------------------
%Approach 2
%Linear equations
A=[1 x(1) x(1)*x(1);1 x(2) x(2)*x(2); 1 x(3) x(3)*x(3)];
W2=A\y
%-------------------------------------------------------------------------
%Approach 3
%Only 2 linear equations
w0=y(2);
w1=-0.5*( y(1)- y(2))+0.5*( y(3)- y(2));
w2=0.5*( y(1)- y(2))+0.5*(y(3)- y(2));
W3=[w0 w1 w2]'
%-------------------------------------------------------------------------
The following figure shows the result of using this method (blue color plot) compare to ordinary zero order hold (black color plot). This method gives much more smoother result but it should be noted that it introduces one sample delay.
The implementation of this method in LabVIEW using C code is shown in the following figure.
The first two approaches involve finding inverse of a 3x3 matrix and I have developed a C program as shown below.
#include
#include
main()
{
    float M[3][3]={{3,0,2},{0,2,0},{2,0,2}}; //initialize a 3x3 matrix
    float N[3][3]={{0,0,0},{0,0,0},{0,0,0}}; //allocate for inverse
    int i,j;
    float d;
    //-------------------------------------------------------------------------
    N[0][0]=(M[1][1]*M[2][2]-M[2][1]*M[1][2]);
    N[1][0]=-(M[1][0]*M[2][2]-M[2][0]*M[1][2]);
    N[2][0]=(M[1][0]*M[2][1]-M[1][1]*M[2][0]);
    d=M[0][0]*N[0][0]+M[0][1]*N[1][0]+M[0][2]*N[2][0];
    N[0][0]/=d;
    N[1][0]/=d;
    N[2][0]/=d;
    N[0][1]=-(M[0][1]*M[2][2]-M[0][2]*M[2][1])/d;
    N[1][1]=(M[0][0]*M[2][2]-M[0][2]*M[2][0])/d;
    N[2][1]=-(M[0][0]*M[2][1]-M[0][1]*M[2][0])/d;
    N[0][2]=(M[0][1]*M[1][2]-M[0][2]*M[1][1])/d;
    N[1][2]=-(M[0][0]*M[1][2]-M[0][2]*M[1][0])/d;
    N[2][2]=(M[0][0]*M[1][1]-M[0][1]*M[1][0])/d;
    //-------------------------------------------------------------------------
    //print 3x3 matrix
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++) printf("%3.4f ",N[i][j]);
        printf("\n");
    }
    getch();
    return 0;
}

Wednesday, March 7, 2012

Skeleton of Image Region

The structural shape of an image region can be represented by a graph. It is achieved by using a thinning algorithm. The resulting graph is called the skeleton of the region. It can be a useful preprocessing step for some applications such as optical character recognition. The following figures shows an original structural shape and its skeleton.
The skeleton of a region is obtained using various methods. Two popular methods among them are Medial Axis Transformation (MAT) , and Two Step Thinning. In Medial Axis Transformation, each point in the region finds its closest neighbour on the boundary of the region. If it finds more than one such neighbour, it belongs to the skeleton of the region. Although MAT is easy to understand, it needs a lot of calculation. We find the distance transform of the region first. The distance transform replaces each pixel value in the region with the distance of the pixel from the nearest neighbour on the boundary of the region. The nearer pixels from the boundary have the lower distance values (lower intensity) and the farther pixels from the boundary have the larger distance values (higher intensity). From the distance values, the local maximums along row or column are searched and defined as pixels in the skeleton. The example MATLAB code for MAT can be seen here (MATeg.m). The original image, the distance transformed image, and the skeleton using MAT are shown in the following figures.


Two Step Thinning algorithm is more efficient and faster than MAT. Two step thinning algorithm iterately delete edge points of a region subject to the constraints that deletion of these points does not remove end points, does not break connectivity, and does not cause excessive erosion of the region. The region points are assumed to have value 1 and background points to have value 0. The method consists of successive passes of two basic steps applied to the given region.
With reference to the 8 neighborhood notation shown in the figure, step 1 flags a contour point p1 for deletion if the following conditions are satisfied: (a) 2 ≤ N(p1) ≤ 6 (b) T(p1) = 1 (c) p2.p4.p6 = 0 (d) p4.p6.p8 = 0 where N(p1) is the number of nonzero neighbors of p1, and T(p1) is the number of 0 to 1 transitions in the ordered sequence p2, p3, ... , p8, p9, p2. In step 2, conditions (a) and (b) remain the same, but conditions (c) and (d) are changed to (c') p2.p4.p8= 0 (d') p2.p6.p8= 0 Step 1 is applied to every border pixel in the binary region under consideration. If one or more of conditions (a)-(d) are violated, the value of the point in question is not changed. If all conditions are satisfied the point is flagged for deletion. However, the point is not deleted until all border points have been processed. This delay prevents changing the structure of the data during execution of the algorithm. After step 1 has been applied to all border points, those that were flagged are deleted (changed to 0). Then step 2 is applied to the resulting data in exactly the same manner as step 1. Thus one iteration of the thinning algorithm consists of (1) applying step 1 to flag border points for deletion; (2) deleting the flagged points; (3) applying step 2 to flag the remaining border points for deletion; and (4) deleting the flagged points. This basic procedure is applied iteratively until no further points are deleted, at which time the algorithm terminates, yielding the skeleton of the region. Condition (c) p2.p4.p6 = 0 and (d) p4.p6.p8 = 0 are satisfied simultaneously by the minimum set of values; (p4 = 0 or p6= 0) or (p2=0 and p8=0). Similarly, conditions (c') and (d') are satisfied simultaneously by the following minimum set of values: (p2=0 or p8=0) or (p4=0 and p6=0). The example MATLAB code for Two Step Thinning algorithm can be seen here (TSTeg.m).
The above codes may be useful to understand the methods and to implement them in other programming languages. In MATLAB, the skeleton of all regions in a binary image is generated via function bwmorph. sk=bwmorph(bwImg,'skel',Inf); The result of the above operation is shown below.

Reference: Rafael C. Gonzalez, Richard E. Woods, Steven L. Eddins, "Digital Image Processing Using MATLAB", Second Edition, Mc Graw Hill (Asia), 2011.

Friday, December 30, 2011

Testing fsolve and anonymous function

I have got a need to solve equations repeatedly whose coefficients are changing with each iteration. MatLab function 'fsolve' is tested using function handle and anonymous function as follows.
s=[3 7 11];
d=[1 3 5];
%ans= (2,1), (5,2), (8,3)
for i=1:3
x0 = [-5; -5]; % Make a starting guess at the solution
myfun =@(x) [x(1) + x(2) - s(i);
x(1) - x(2) - d(i)];
[x,fval] = fsolve(myfun,x0)  % Call 
end

Friday, December 16, 2011

Geometric Template Matching in LabVIEW

In NI's IMAQ Vision Concepts Manual, geometric template matching is described as follows. Geometric matching locates regions in a grayscale image that match a model, or template, of a reference pattern. Geometric matching is specialized to locate templates that are characterized by distinct geometric or shape information. When using geometric matching, a template is created that represents the object to be searched. Machine vision application then searches for instances of the template in each inspection image and calculates a score for each match. The score relates how closely the template resembles the located matches. Geometric matching finds template matches regardless of lighting variation, blur, noise, occlusion, and geometric transformations such as shifting, rotation, or scaling of the template.
The VIs such as IMAQ Find CoordSys (Pattern) 2 are used to locate the model. The template for the model is created as discussed in the following steps.
Open Template Editor in Windows by clicking Start -> All Programs -> National Instruments -> Vision -> Template Editor. Click File menu->New Template.... Select Geometric Matching Template (Edge Based) and browse an image to extract the template from. In the Select Template Region tab, define a region. For example, start at (200,300) and drag the mouse cursor to (232,332) and release it. Then, you can move the selection to the desired location. In the Define curves tab, specify curve parameters, e.g., Extraction mode to normal, Edge Threshold to 32, Edge Filter size to Fine, Minimum Length to 5, Row Search Step Size to 1 and Column Search Step size to 1. The setting in Customize Scoring and Specify Match Options tabs are set as default. Save the template by clicking File -> Save Template....
As an example, I have created a few VIs at the following link.

Geometric Template Matching on GitHub

Initialization for the VI inputs is shown below.

Friday, June 3, 2011

Curve Fitting in Matlab

One of my friends was doing analysis of some sampled data. He wanted to fit them into a curve to derive the equation. He said Excel could fit up to polynomial of order 6 and he wanted a higher order one. So, he asked my help to write a Matlab program. He also wanted the plotted curve besides the calculated coefficients. The program and sample data are shown below. That is good for me because I also need to fit data occasionally and I can reuse it later :)
See d.txt and cf.m.
%--------------------------------------
%Curve fitting
%2011-Jun-03
%Programmer: Yan Naing Aye
%--------------------------------------
clc;
close all;
clear all;
%--------------------------------------
%get data from file that can be edited
load('d.txt');
X=d(:,1);
Y=d(:,2);
%--------------------------------------
%define order
N=2;
%--------------------------------------
%curve fitting
p=polyfit(X,Y,N);
%generate curve fitted data
[nr nc]=size(X);
YA=zeros(nr,1);
for i=0:N
    YA=YA+p(i+1)*X.^(N-i);
end
%--------------------------------------
%Plot Y vs X
figure;
plot(X,Y,' rd','LineWidth',2,...
                'MarkerEdgeColor','k',...
                'MarkerFaceColor','g',...
                'MarkerSize',6)
hold on;
plot(X,YA,'b','LineWidth',2,...
                'MarkerEdgeColor','k',...
                'MarkerFaceColor','g',...
                'MarkerSize',6)
hold off;            
grid on;
Title('Y vs X')
xlabel('X');
ylabel('Y');
legend('Sampled data','Fitted curve',...
       'Location','NW')
%--------------------------------------

Monte Carlo integration

As I am reading about Particle Filter, just for fun, I wrote a Matlab program that performs Monte Carlo integration using uniform distribution. The equation and the program are as follows.
clc;
close all;
clear all;
%--------------------------------------
%Monte Carlo Integration
%--------------------------------------
%--------------------------------------
%limits
LowerLimit=1;
UpperLimit=3;
%--------------------------------------
%generate uniformly distributed random 
%numbers within the range
n=10000;
x=LowerLimit+(UpperLimit-LowerLimit)*rand(n,1);
%--------------------------------------
%Probability distribution function for 
%uniformly distributed random numbers
q=1/(UpperLimit-LowerLimit);
%--------------------------------------
%function to integrate
f=3.*x.*x;
i=mean(f./q)
%--------------------------------------

Tuesday, May 3, 2011

Byte Stuffing

I occasionally need to write programs to send and receive data bytes from one device to another. That is why I arbitrarily choose a simple variant of byte stuffing methods to build frames to send and receive data. To delimit the frame, control characters - 0x02 and 0x03- are defined as start of text (STX) and end of text (ETX) respectively. For error detection, exclusive-or of data bytes is appended after the ETX as a checksum. If you need better error detection, CRC as described at

CRC Calculation in VB and C

can also be used.

For example, if we want to send two bytes of data -
0x30 0x31,
the resulting frame will be
0x02 0x30 0x31 0x03 0x01
,where 0x02 at the start is added as STX, followed by data bytes and the byte before the last one, 0x03, is added as ETX. Since the exclusive-or of data bytes, 0x02^0x03, is 0x01, it is appended at the end as checksum. How can we send data that contains 0x02 or 0x03 which were already used as control characters? We need to define another control character 0x10 as Data Link Escape (DLE) to mark data that are not control characters. As an another example, let us build a frame for five data bytes -
0x30 0x02 0x65 0x10 0x03.
We will do byte stuffing by putting DLE in front of every data byte that conflicts with STX, ETX, or DLE. And
0x02 0x30 0x10 0x02 0x65 0x10 0x10 0x10 0x03 0x03 0x44
will be the resulting frame. I have developed a few programs in C and LabVIEW. Example programs can be downloaded at the following links.

Byte Stuffing on GitHub


The following is the C++ code to build, send and receive a frame.
// Byte stuffing- sending and receiving frames
// Author: Yan Naing Aye

#ifndef  FRAME_H
#define FRAME_H

#include 
#define STX 0x02
#define ETX 0x03
#define DLE 0x10

#define TX_BUF_SIZE 128
#define RX_BUF_SIZE 128
enum RX_STATE { IGNORE,RECEIVING,ESCAPE,RXCRC1,RXCRC2 };
//-----------------------------------------------------------------------------
class Frame {    
    RX_STATE rState;
protected:
    int TxN;//number of transmitting bytes
    int RxN;//number of receiving bytes
    char tb[TX_BUF_SIZE];//transmit buffer
    char rb[RX_BUF_SIZE];//receiving data
public:
    Frame();
    int setTxFrame(char* d,int n);
    unsigned int CRC16CCITT_Calculate(char* s,unsigned char len,unsigned int crc);
    int getTxN();
    int getRxN();
    int receiveRxFrame(char c);//get receiving frame from received char
    char* getTxBuf();
    char* getRxBuf();
};
//-----------------------------------------------------------------------------
Frame::Frame():TxN(0),RxN(0),rState(IGNORE){}
//-----------------------------------------------------------------------------
char* Frame::getTxBuf(){
    return tb;
}
//-----------------------------------------------------------------------------
char* Frame::getRxBuf(){
    return rb;
}
//-----------------------------------------------------------------------------
//Prepare transmitting frame
int Frame::setTxFrame(char* d,int n)
{
    unsigned int txcrc=0xFFFF;//initialize crc
    char c;
    int i=0,j=0;
    tb[i++]=STX;//start of frame
    for(j=0;j < n;j++) {
        c=d[j];
        if((c==STX)||(c==ETX)||(c==DLE)) tb[i++]=(DLE);
        tb[i++]=c;
    }
    tb[i++]=(ETX);//end of frame

    txcrc=CRC16CCITT_Calculate(d,n,txcrc);//calculate crc
    tb[i++]=txcrc & 0xFF;
    tb[i++]=(txcrc >> 8) & 0xFF;
    TxN=i;
    return TxN;
}
//-----------------------------------------------------------------------------
//Inputs
//s : pointer to input char string
//len: string len (maximum 255)
//crc: initial CRC value

//Output
//Returns calculated CRC
unsigned int Frame::CRC16CCITT_Calculate(char* s,unsigned char len,unsigned int crc)
{
    //CRC Order: 16
    //CCITT(recommendation) : F(x)= x16 + x12 + x5 + 1
    //CRC Poly: 0x1021
    //Operational initial value:  0xFFFF
    //Final xor value: 0
    unsigned char i,j;
    for(i=0;i < len;i++,s++) {
        crc^=((unsigned int)(*s) & 0xFF) << 8;
        for(j=0;j<8;j++) {
            if(crc & 0x8000) crc=(crc << 1)^0x1021;
            else crc <<=1;
        }
    }
    return (crc & 0xFFFF);//truncate last 16 bit
}
//-----------------------------------------------------------------------------
//get number of transmitting bytes
int Frame::getTxN()
{
    return TxN;
}
//-----------------------------------------------------------------------------
//get number of transmitting bytes
int Frame::getRxN()
{
    return RxN;
}
//-----------------------------------------------------------------------------
//process receiving char
int Frame::receiveRxFrame(char c)
{
    static char b;
    unsigned int crc;
    unsigned int rxcrc=0xFFFF;//initialize CRC
    switch(rState){
        case IGNORE:
            if(c==STX) { rState=RECEIVING;RxN=0;}
            break;
        case RECEIVING:
            if(c==STX) { rState=RECEIVING;RxN=0;}
            else if(c==ETX){rState=RXCRC1;}
            else if(c==DLE){ rState=ESCAPE; }
            else { rb[RxN++]=c; }
            break;
        case ESCAPE:
            rb[RxN++]=c; rState=RECEIVING;
            break;
        case RXCRC1:
            b=c; rState=RXCRC2;
            break;
        case RXCRC2:
            rState=IGNORE;
            crc=( (int)c << 8 | ((int)b & 0xFF) ) & 0xFFFF;//get received crc
            rxcrc=CRC16CCITT_Calculate(rb,RxN,rxcrc);//calculate crc
            //printf("crc: %x  rxcrc:%x \n",crc,rxcrc);
            if(rxcrc==crc){return RxN;}//if crc is correct            
            else {RxN=0;}//discard the frame

            break;
    }
    return 0;
}

//-----------------------------------------------------------------------------

//#############################################################################

class Frame2:public Frame {
    char Dt[20];//transmitting data
public:
    Frame2();
    void printTxFrame();
    void printRxFrame();
    void printRxData();
    void setTxData(float x,float y,float z,float b,float t);
};
//-----------------------------------------------------------------------------
Frame2::Frame2():Frame(),Dt(""){}
//-----------------------------------------------------------------------------
//Print out frame content
void Frame2::printTxFrame()
{
    printf("Tx frame buffer: ");
    for(int j=0;j < TxN;j++) printf("%02X ",(unsigned char)tb[j]);
    printf("\n");
}
//-----------------------------------------------------------------------------
//Print out frame content
void Frame2::printRxFrame()
{
    printf("Rx data buffer: ");
    for(int j=0;j < RxN;j++) printf("%02X ",(unsigned char)rb[j]);
    printf("\n");
}
//-----------------------------------------------------------------------------
//Set transmitting data
void Frame2::setTxData(float x,float y,float z,float b,float t)
{
    *(float*)(Dt)=x;
    *(float*)(Dt+4)=y;
    *(float*)(Dt+8)=z;
    *(float*)(Dt+12)=b;
    *(float*)(Dt+16)=t;
    Frame::setTxFrame(Dt,20);
}
//-----------------------------------------------------------------------------
//Print out received data
void Frame2::printRxData()
{
    float x,y,z,b,t;
    x=*(float*)(Dt);
    y=*(float*)(Dt+4);
    z=*(float*)(Dt+8);
    b=*(float*)(Dt+12);
    t=*(float*)(Dt+16);
    printf("Rx data: %f %f %f %f %f \n",x,y,z,b,t);
}
//-----------------------------------------------------------------------------

#endif // FRAME_H

Friday, June 18, 2010

Common Interrupt Pitfalls

I just want to share some interesting facts that I found in SDCC Compiler User Guide. From my experience, I think these facts are very important to keep in mind of a firmware programmer. Last time, I got an experience that my program executed wrongly even though I could not find any fault in my program. Suddenly, I remembered stack overflow problem and the program worked correctly after I changed the stack size.


Variable not declared volatile

If an interrupt service routine changes variables which are accessed by other functions these variables have to be declared volatile. See http://en.wikipedia.org/wiki/Volatile_variable.

Non-atomic access

If the access to these variables is not atomic (i.e. the processor needs more than one instruction for the access and could be interrupted while accessing the variable) the interrupt must be disabled during the access to avoid inconsistent data. Access to 16 or 32 bit variables is obviously not atomic on 8 bit CPUs and should be protected by disabling interrupts. You’re not automatically on the safe side if you use 8 bit variables though. For example, on the 8051 the harmless looking ”flags |= 0x80;” is not atomic if flags resides in xdata. Setting ”flags |= 0x40;” from within an interrupt routine might get lost if the interrupt occurs at the wrong time. ”counter += 8;” is not atomic on the 8051 even if counter is located in data memory. Bugs like these are hard to reproduce and can cause a lot of trouble.

Stack overflow

The return address and the registers used in the interrupt service routine are saved on the stack so there must be sufficient stack space. If there isn’t enough stack space, variables or registers (or even the return address itself) will be corrupted. This stack overflow is most likely to happen if the interrupt occurs during the ”deepest” subroutine when the stack is already in use for i.e. many return addresses.

Use of non-reentrant functions

Calling other functions from an interrupt service routine is not recommended, avoid it if possible. Furthermore nonreentrant functions should not be called from the main program while the interrupt service routine might be active. They also must not be called from low priority interrupt service routines while a high priority interrupt service routine might be active. You could use semaphores or make the function critical if all parameters are passed in registers. Good luck with your programming!