detect to rising, stable and falling point in non-smooth rectangular wave
The usual approach to change detection is the CUSUM algorithm.

I've done an implementation that just addresses the level (mean) change issue. It's included (in R) below.

The black line is the noise-free data, the red line is the noisy data and the blue bars are the detected breaks (for this realization).

This just addresses the level change; to address the three zones: low level, changing level, and high level, you'll need to figure out the way to estimate the mean in the changing level (perhaps assume a rise time and fix the two levels?).  

The code below is based on this document.



A slight change might get you the first and second changes easily: instead of working with the data, work with the difference of the data.  If I do that, then I get:



but I've had to add:

sigma &lt;- 0.001
data_before_diff &lt;- noiseless_data + rnorm(length(noiseless_data),0,sigma)
data &lt;- diff(data_before_diff)
mu2diff &lt;- 0.04
thresh &lt;- 1


and then later:

 s[k] = (mu2diff - mu1)/sigma*(data[k] - (mu2diff + mu1)/2)


and

    tmp &lt;- mu1
    mu1 &lt;- mu2diff
    mu2diff &lt;- tmp


To find the changes at the end of the signal, you'll probably need to change mu2diff to -mu2diff and check for that versus 0.

Note I've had to greatly reduce the noise variance and thus the threshold to get this to work.



R Code Below

# 30039
# CUSUM 

N &lt;- 30

mu1 &lt;- 0
mu2 &lt;- 1
noiseless_data &lt;- c(rep(mu1,N), seq(mu1,mu2,1/N), rep(mu2,N*4), seq(mu2,mu1,-1/N), rep(mu1,N))


sigma &lt;- 0.1
data &lt;- noiseless_data + rnorm(length(noiseless_data),0,sigma)

thresh &lt;- 100

breaks &lt;- rep(0,N)
num_breaks &lt;- 0

s &lt;- rep(0,length(data))
capS &lt;- rep(0,length(data))
G &lt;- rep(0,length(data))
for (k in 1:length(data))
{
  s[k] = (mu2 - mu1)/sigma*(data[k] - (mu2+mu1)/2)
  if (k==1)
  {
    capS[k] = s[k]
  }
  else
  {
    capS[k] = capS[k-1] + s[k]
  }

  G[k] &lt;- max(0,capS[k] - min(capS[1:k]))

  if (abs(G[k]) &gt; thresh)
  {
    #capS[k] &lt;- 0
    num_breaks &lt;- num_breaks + 1
    breaks[num_breaks] &lt;- which.min(capS[1:k])
    tmp &lt;- mu1
    mu1 &lt;- mu2
    mu2 &lt;- tmp
  }
}

first_break &lt;- min(breaks[1:num_breaks])
last_break &lt;- max(breaks[1:num_breaks])

plot(data,col="red", type="l")
lines(noiseless_data)
lines(c(first_break,first_break),c(0,1),col="blue", lwd=10)
lines(c(last_break,last_break),c(0,1),col="blue",lwd=10)