Waveform T-Shirt
In one of the last few videos from Keysight Labs, I saw a nice design for a T-shirt. The video was about copying signals from a remote control to ‘automatically’ drive a radio controlled car with the help of a function generator. On the T-shirt of the presenter, there are the basic signals (sine, triangle, square and sawtooth) in different colors.
We recently got a new toy. A desktop cutting machine for paper and also flexing material to put on clothing.

The program that comes with the cutter generates some code from your design to let the cutter cut the material. Because it’s vectorbased something like a .svg file is recommended.
Creating the signals
For the sake of overcomplicating things, it’s nice to have some sort of function behind the drawings on the T-shirt. So I wrote a few Python programs to create the signals with their .svg file. I also added a ‘flat’ line around the signals.
Sine wave
# Sine wave
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
def cm_to_inch(value):
return value/2.54
# Defining 'constants'
NUMBER_OF_PERIODS = 2.5
LINEWIDTH = 20
plt.figure(figsize=(cm_to_inch(28),cm_to_inch(6)))
FLATLINE_LENGHT = 1.5
# Calculating variables
numberOfPeriodsRadian = 2*np.pi*NUMBER_OF_PERIODS
# Time array with number of periods
t = np.arange(0, numberOfPeriodsRadian, 0.001)
# Wave
sinWave = np.sin(t)
#squareWave = signal.square(t)
# Shift time t
t = t + FLATLINE_LENGHT
# Total wave with flatlines
totalWave = np.insert(sinWave, 0, 0)
t = np.insert(t, 0, 0)
totalWave = np.append(totalWave, 0)
t = np.append(t, t[-1]+FLATLINE_LENGHT) # last element with flatline offset
# Plot the sine wave signal
plt.plot(t, totalWave, '#FFDF2C', linewidth=LINEWIDTH)
# Min and max values for the x and y axis
plt.ylim(-1.3, 1.3)
plt.xlim(0,numberOfPeriodsRadian+2*FLATLINE_LENGHT)
# Turn off the axis and zoom
plt.axis('off')
plt.gca().set_position([0, 0, 1, 1])
# Save and show the plot
plt.savefig("sine_wave.png", transparent=True, frameon=True) #https://stackoverflow.com/a/62205073/13540083
plt.show()

Square wave
# Square wave
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
def cm_to_inch(value):
return value/2.54
# Defining 'constants'
NUMBER_OF_PERIODS = 2.5
LINEWIDTH = 20
plt.figure(figsize=(cm_to_inch(28),cm_to_inch(6)))
FLATLINE_LENGHT = 1.5
# Calculating variables
numberOfPeriodsRadian = 2*np.pi*NUMBER_OF_PERIODS
# Time array with number of periods
t = np.arange(0, numberOfPeriodsRadian, 0.001)
# Wave
squareWave = signal.square(t)
# Shift time t
t = t + FLATLINE_LENGHT
# Total wave with flatlines
totalWave = np.insert(squareWave, 0, 1)
t = np.insert(t, 0, 0)
totalWave = np.append(totalWave, 1)
t = np.append(t, t[-1]+FLATLINE_LENGHT) # last element with flatline offset
# Plot the sine wave signal
plt.plot(t, totalWave, 'g', linewidth=LINEWIDTH)
# Min and max values for the x and y axis
plt.ylim(-1.3, 1.3)
plt.xlim(0,numberOfPeriodsRadian+2*FLATLINE_LENGHT)
# Turn off the axis and zoom
plt.axis('off')
plt.gca().set_position([0, 0, 1, 1])
# Save and show the plot
plt.savefig("square_wave.png", transparent=True, frameon=True)
plt.show()

Triangle wave
# Triangle wave
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
def cm_to_inch(value):
return value/2.54
# Defining 'constants'
NUMBER_OF_PERIODS = 2.5
LINEWIDTH = 20
plt.figure(figsize=(cm_to_inch(28),cm_to_inch(6)))
FLATLINE_LENGHT = 1.5
# Calculating variables
numberOfPeriodsRadian = 2*np.pi*NUMBER_OF_PERIODS
# Time array with number of periods
t = np.arange(0+0.5*np.pi, numberOfPeriodsRadian+0.5*np.pi, 0.001)
# Wave
triangleWave = signal.sawtooth(t, 0.5) # a triangle wave is a sawtooth with a 0.5 duty cycle
# No shifting needed
# Total wave with flatlines
totalWave = np.insert(triangleWave, 0, 0)
t = np.insert(t, 0, 0)
totalWave = np.append(totalWave, 0)
t = np.append(t, t[-1]+FLATLINE_LENGHT) # last element with flatline offset
# Plot the sine wave signal
plt.plot(t, totalWave, 'r', linewidth=LINEWIDTH)
# Min and max values for the x and y axis
plt.ylim(-1.3, 1.3)
plt.xlim(0,numberOfPeriodsRadian+2*FLATLINE_LENGHT)
# Turn off the axis and zoom
plt.axis('off')
plt.gca().set_position([0, 0, 1, 1])
# Save and show the plot
plt.savefig("triangle_wave.png", transparent=True, frameon=True)
plt.show()

Sawtooth wave
# Sawtooth wave
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
def cm_to_inch(value):
return value/2.54
# Defining 'constants'
NUMBER_OF_PERIODS = 2.5
LINEWIDTH = 20
plt.figure(figsize=(cm_to_inch(28),cm_to_inch(6)))
FLATLINE_LENGHT = 1.5
# Calculating variables
numberOfPeriodsRadian = 2*np.pi*NUMBER_OF_PERIODS
# Time array with number of periods
t = np.arange(0+np.pi, numberOfPeriodsRadian+np.pi, 0.001)
# Wave
sawtoothWave = signal.sawtooth(t)
# Time shifting
t = t - FLATLINE_LENGHT
# Total wave with flatlines and extra endpoint for the sawtooth
totalWave = np.insert(sawtoothWave, 0, 0)
t = np.insert(t, 0, 0)
totalWave = np.append(totalWave, 0)
t = np.append(t, t[-1]+0.001)
totalWave = np.append(totalWave, 0)
t = np.append(t, t[-1]+FLATLINE_LENGHT) # last element with flatline offset
# Plot the sine wave signal
plt.plot(t, totalWave, '#2EA6FF', linewidth=LINEWIDTH)
# Min and max values for the x and y axis
plt.ylim(-1.3, 1.3)
plt.xlim(0,numberOfPeriodsRadian+2*FLATLINE_LENGHT)
# Turn off the axis and zoom
plt.axis('off')
plt.gca().set_position([0, 0, 1, 1])
# Save and show the plot
plt.savefig("sawtooth_wave.png", transparent=True, frameon=True)
plt.show()

As you can see the signals are exported as .png instead of the earlier .svg. This is because the cutter software didn’t recognised the flat lines in front of the triangle and sawtooth waves. Therefore I exported them as .png with a width of 28 cm and an height of 6 cm.
The lenght of all the waves is 2.5 periods. The flat line is 1.5 on each side. That means the total lenght of the signal is (2.5*pi+2*1.5≈)10.85.
Cutting the flex material
The .png files are loaded into the program of the cutting machine. Then you can start the cutting.


After cutting you need to remove the parts you don’t want on the T-shirt. Then you can put it on the cloting and attach it with a iron and some baking paper in between.



The result on the test piece came out great so now on to the other waveforms. As you can see I swapped the color of the triangle and sawtooth waveforms.
I marked the middle line of the T-shirt with chalk. We also got the idea of using an aligning paper. We cutted all the waveforms out of paper (A3) with the right spacing. The translucent foils has some stickiness to it so it stays on the T-shirt while aligning.
When attaching the waveforms we used baking foil between the signals and the iron. Of course we removed the aligning paper.
The setting of the iron was ‘cotton’ and most of time the flex material is attached when ironing 40 seconds. Make sure you pat and don’t slide the iron around. Otherwise the glue can be visible after attaching.





QR-code
To add a bit more personality to the T-shirt I added a QR-code to the sleeve. The QR-code was generated with the Segno library for Python. I used the black of the shirt as the black color of the QR-code.
Because the cutting program did weird with the .svg file, we used Inkscape to scale the image and exported it as .png.
For cutting it’s very important to horizontally mirror the images (also for the signals). Otherwise you will get a mirrored image…
import segno
qr = segno.make('https://design.klop4you.nl/home/?p=340')
qr.save('qrcode_segno.svg')


The QR-code works fine, but when wearing the T-shirt the QR-code is a little bit bent. The reader I used (Google Lens) then works less good. This is a good point to keep in mind. It probalby works better on the front or back of the shirt.
End result
Overall the end result came out grate for a first flex material test/T-shirt. Also the colors really match with the black.

Thanks for reading!


Recent Comments